From f38fc13fba64a9f591a8a16f785afa9cd6524c80 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 23 Jun 2011 14:10:35 -0400 Subject: [PATCH] --- yaml --- r: 257867 b: refs/heads/master c: c6cb13f9fef2e401d9fbb0709d088e7c50fe7aea h: refs/heads/master i: 257865: 5c181b284e73568d5fde4e61a49e7276d679421d 257863: 388d5847ada3234d42c5d9f35a70a4a51a514642 v: v3 --- [refs] | 2 +- .../DocBook/writing-an-alsa-driver.tmpl | 10 +- trunk/Documentation/cgroups/cpuacct.txt | 2 +- trunk/Documentation/cgroups/cpusets.txt | 2 +- trunk/Documentation/filesystems/Locking | 8 +- trunk/Documentation/filesystems/porting | 27 +- trunk/Documentation/filesystems/vfs.txt | 30 +- .../sound/alsa/HD-Audio-Controls.txt | 100 - trunk/Documentation/sysctl/kernel.txt | 215 +- trunk/MAINTAINERS | 18 +- trunk/arch/arm/mach-tegra/clock.c | 7 +- trunk/arch/arm/mach-ux500/clock.c | 31 +- trunk/arch/arm/plat-omap/clock.c | 12 +- trunk/arch/arm/plat-samsung/clock.c | 7 +- trunk/arch/arm/plat-spear/clock.c | 7 +- trunk/arch/blackfin/include/asm/Kbuild | 43 + trunk/arch/blackfin/include/asm/auxvec.h | 1 - trunk/arch/blackfin/include/asm/bitsperlong.h | 1 - trunk/arch/blackfin/include/asm/bugs.h | 1 - trunk/arch/blackfin/include/asm/cputime.h | 1 - trunk/arch/blackfin/include/asm/current.h | 1 - trunk/arch/blackfin/include/asm/device.h | 1 - trunk/arch/blackfin/include/asm/div64.h | 1 - .../blackfin/include/asm/emergency-restart.h | 1 - trunk/arch/blackfin/include/asm/errno.h | 1 - trunk/arch/blackfin/include/asm/fb.h | 1 - trunk/arch/blackfin/include/asm/futex.h | 1 - trunk/arch/blackfin/include/asm/hw_irq.h | 1 - trunk/arch/blackfin/include/asm/ioctl.h | 1 - trunk/arch/blackfin/include/asm/ipcbuf.h | 1 - trunk/arch/blackfin/include/asm/irq_regs.h | 1 - trunk/arch/blackfin/include/asm/kdebug.h | 1 - trunk/arch/blackfin/include/asm/kmap_types.h | 1 - trunk/arch/blackfin/include/asm/local.h | 1 - trunk/arch/blackfin/include/asm/local64.h | 1 - trunk/arch/blackfin/include/asm/mman.h | 1 - trunk/arch/blackfin/include/asm/msgbuf.h | 1 - trunk/arch/blackfin/include/asm/param.h | 1 - trunk/arch/blackfin/include/asm/percpu.h | 1 - trunk/arch/blackfin/include/asm/pgalloc.h | 1 - trunk/arch/blackfin/include/asm/resource.h | 1 - trunk/arch/blackfin/include/asm/scatterlist.h | 6 - trunk/arch/blackfin/include/asm/sembuf.h | 1 - trunk/arch/blackfin/include/asm/serial.h | 1 - trunk/arch/blackfin/include/asm/setup.h | 1 - trunk/arch/blackfin/include/asm/shmbuf.h | 1 - trunk/arch/blackfin/include/asm/shmparam.h | 1 - trunk/arch/blackfin/include/asm/socket.h | 1 - trunk/arch/blackfin/include/asm/sockios.h | 1 - trunk/arch/blackfin/include/asm/statfs.h | 1 - trunk/arch/blackfin/include/asm/termbits.h | 1 - trunk/arch/blackfin/include/asm/termios.h | 1 - trunk/arch/blackfin/include/asm/topology.h | 1 - trunk/arch/blackfin/include/asm/types.h | 1 - trunk/arch/blackfin/include/asm/ucontext.h | 1 - trunk/arch/blackfin/include/asm/unaligned.h | 1 - trunk/arch/blackfin/include/asm/user.h | 1 - trunk/arch/blackfin/include/asm/xor.h | 1 - trunk/arch/ia64/kvm/Kconfig | 1 + trunk/arch/mips/Kconfig | 16 + trunk/arch/powerpc/kvm/Kconfig | 1 + .../arch/powerpc/platforms/cell/spufs/file.c | 11 +- .../arch/powerpc/platforms/cell/spufs/inode.c | 29 +- .../arch/powerpc/platforms/cell/spufs/spufs.h | 2 +- .../powerpc/platforms/cell/spufs/syscalls.c | 22 +- trunk/arch/s390/kvm/Kconfig | 1 + trunk/arch/sh/Kconfig | 16 + trunk/arch/tile/kvm/Kconfig | 1 + trunk/arch/um/sys-i386/Makefile | 3 +- trunk/arch/x86/Kconfig | 16 +- trunk/arch/x86/Kconfig.cpu | 3 - trunk/arch/x86/boot/Makefile | 9 +- trunk/arch/x86/boot/tools/build.c | 33 +- trunk/arch/x86/include/asm/apb_timer.h | 22 +- trunk/arch/x86/include/asm/cmpxchg_32.h | 48 - trunk/arch/x86/include/asm/cmpxchg_64.h | 45 - trunk/arch/x86/include/asm/cpufeature.h | 2 - trunk/arch/x86/kernel/apb_timer.c | 409 +- trunk/arch/x86/kernel/apic/apic.c | 22 +- trunk/arch/x86/kernel/cpu/bugs.c | 4 - trunk/arch/x86/kernel/cpu/hypervisor.c | 4 +- trunk/arch/x86/kernel/quirks.c | 5 +- trunk/arch/x86/kernel/relocate_kernel_32.S | 2 - trunk/arch/x86/kernel/relocate_kernel_64.S | 2 - trunk/arch/x86/kernel/tsc.c | 24 + trunk/arch/x86/kvm/Kconfig | 1 + trunk/block/blk-core.c | 3 - trunk/block/blk-exec.c | 7 - trunk/drivers/Kconfig | 2 - trunk/drivers/base/Kconfig | 2 - trunk/drivers/base/Makefile | 1 - trunk/drivers/base/devtmpfs.c | 337 +- trunk/drivers/base/regmap/Kconfig | 13 - trunk/drivers/base/regmap/Makefile | 3 - trunk/drivers/base/regmap/regmap-i2c.c | 115 - trunk/drivers/base/regmap/regmap-spi.c | 72 - trunk/drivers/base/regmap/regmap.c | 455 - trunk/drivers/block/pktcdvd.c | 2 +- trunk/drivers/char/generic_nvram.c | 4 - trunk/drivers/char/nvram.c | 2 - trunk/drivers/char/ps3flash.c | 13 +- trunk/drivers/clocksource/Kconfig | 3 - trunk/drivers/clocksource/Makefile | 1 - trunk/drivers/clocksource/dw_apb_timer.c | 401 - trunk/drivers/firmware/iscsi_ibft.c | 14 +- trunk/drivers/macintosh/nvram.c | 4 - trunk/drivers/md/md.c | 26 +- trunk/drivers/mtd/ubi/cdev.c | 10 +- trunk/drivers/regulator/Kconfig | 1 - trunk/drivers/regulator/tps65023-regulator.c | 97 +- trunk/drivers/scsi/aha152x.c | 17 +- trunk/drivers/scsi/atari_NCR5380.c | 6 +- trunk/drivers/scsi/atari_scsi.c | 1 - trunk/drivers/scsi/be2iscsi/be_main.c | 199 +- trunk/drivers/scsi/bfa/Makefile | 2 +- trunk/drivers/scsi/bfa/bfa.h | 144 +- trunk/drivers/scsi/bfa/bfa_core.c | 878 +- trunk/drivers/scsi/bfa/bfa_defs.h | 583 +- trunk/drivers/scsi/bfa/bfa_defs_fcs.h | 27 +- trunk/drivers/scsi/bfa/bfa_defs_svc.h | 170 +- trunk/drivers/scsi/bfa/bfa_fc.h | 11 +- trunk/drivers/scsi/bfa/bfa_fcbuild.c | 49 +- trunk/drivers/scsi/bfa/bfa_fcbuild.h | 16 +- trunk/drivers/scsi/bfa/bfa_fcpim.c | 478 +- trunk/drivers/scsi/bfa/bfa_fcpim.h | 89 +- trunk/drivers/scsi/bfa/bfa_fcs.c | 153 +- trunk/drivers/scsi/bfa/bfa_fcs.h | 31 +- trunk/drivers/scsi/bfa/bfa_fcs_fcpim.c | 10 - trunk/drivers/scsi/bfa/bfa_fcs_lport.c | 329 +- trunk/drivers/scsi/bfa/bfa_fcs_rport.c | 121 +- trunk/drivers/scsi/bfa/bfa_hw_cb.c | 94 +- trunk/drivers/scsi/bfa/bfa_hw_ct.c | 89 +- trunk/drivers/scsi/bfa/bfa_ioc.c | 2992 +-- trunk/drivers/scsi/bfa/bfa_ioc.h | 609 +- trunk/drivers/scsi/bfa/bfa_ioc_cb.c | 69 +- trunk/drivers/scsi/bfa/bfa_ioc_ct.c | 516 +- trunk/drivers/scsi/bfa/bfa_modules.h | 27 +- trunk/drivers/scsi/bfa/bfa_port.c | 428 +- trunk/drivers/scsi/bfa/bfa_port.h | 62 +- trunk/drivers/scsi/bfa/bfa_svc.c | 1136 +- trunk/drivers/scsi/bfa/bfa_svc.h | 151 +- trunk/drivers/scsi/bfa/bfad.c | 295 +- trunk/drivers/scsi/bfa/bfad_attr.c | 53 +- trunk/drivers/scsi/bfa/bfad_bsg.c | 2163 -- trunk/drivers/scsi/bfa/bfad_bsg.h | 509 - trunk/drivers/scsi/bfa/bfad_debugfs.c | 14 +- trunk/drivers/scsi/bfa/bfad_drv.h | 26 +- trunk/drivers/scsi/bfa/bfad_im.c | 32 +- trunk/drivers/scsi/bfa/bfad_im.h | 3 - trunk/drivers/scsi/bfa/bfi.h | 637 +- trunk/drivers/scsi/bfa/bfi_cbreg.h | 305 + trunk/drivers/scsi/bfa/bfi_ctreg.h | 636 + trunk/drivers/scsi/bfa/bfi_ms.h | 159 +- trunk/drivers/scsi/bfa/bfi_reg.h | 450 - trunk/drivers/scsi/bnx2fc/bnx2fc.h | 8 +- trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 31 +- trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c | 24 +- trunk/drivers/scsi/bnx2fc/bnx2fc_io.c | 2 +- .../drivers/scsi/bnx2i/57xx_iscsi_constants.h | 2 +- trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h | 2 +- trunk/drivers/scsi/bnx2i/bnx2i.h | 33 +- trunk/drivers/scsi/bnx2i/bnx2i_hwi.c | 199 +- trunk/drivers/scsi/bnx2i/bnx2i_init.c | 153 +- trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c | 38 +- trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c | 2 +- trunk/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c | 4 +- trunk/drivers/scsi/fcoe/fcoe.c | 174 +- trunk/drivers/scsi/fnic/fnic.h | 2 +- trunk/drivers/scsi/fnic/fnic_main.c | 21 +- trunk/drivers/scsi/fnic/fnic_scsi.c | 2 +- trunk/drivers/scsi/iscsi_boot_sysfs.c | 31 +- trunk/drivers/scsi/iscsi_tcp.c | 61 +- trunk/drivers/scsi/libfc/fc_exch.c | 26 +- trunk/drivers/scsi/libfc/fc_lport.c | 2 - trunk/drivers/scsi/libfc/fc_rport.c | 14 - trunk/drivers/scsi/libiscsi.c | 14 +- trunk/drivers/scsi/libiscsi_tcp.c | 14 +- trunk/drivers/scsi/lpfc/lpfc_debugfs.c | 3 +- trunk/drivers/scsi/mac_scsi.c | 14 +- trunk/drivers/scsi/mpt2sas/mpi/mpi2.h | 12 +- trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 74 +- trunk/drivers/scsi/mpt2sas/mpi/mpi2_init.h | 6 +- trunk/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 4 +- trunk/drivers/scsi/mpt2sas/mpt2sas_base.c | 84 +- trunk/drivers/scsi/mpt2sas/mpt2sas_base.h | 77 +- trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c | 12 +- trunk/drivers/scsi/mpt2sas/mpt2sas_debug.h | 2 +- trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c | 279 +- .../drivers/scsi/mpt2sas/mpt2sas_transport.c | 24 +- trunk/drivers/scsi/scsi_devinfo.c | 2 - trunk/drivers/scsi/scsi_lib.c | 2 - trunk/drivers/scsi/ses.c | 6 +- trunk/drivers/scsi/sr.c | 46 +- trunk/drivers/scsi/sr.h | 7 - trunk/drivers/scsi/sun3_NCR5380.c | 98 +- trunk/drivers/scsi/sun3_scsi.c | 11 +- trunk/drivers/scsi/sun3_scsi_vme.c | 11 +- trunk/drivers/sh/clk/core.c | 7 +- trunk/drivers/staging/pohmelfs/dir.c | 2 +- trunk/drivers/staging/pohmelfs/inode.c | 11 +- trunk/drivers/target/tcm_fc/tfc_cmd.c | 26 +- trunk/drivers/usb/gadget/printer.c | 5 +- trunk/drivers/video/fb_defio.c | 11 +- trunk/drivers/virtio/Kconfig | 3 - trunk/fs/9p/acl.c | 4 +- trunk/fs/9p/acl.h | 2 +- trunk/fs/9p/cache.c | 20 +- trunk/fs/9p/cache.h | 9 + trunk/fs/9p/v9fs.c | 45 +- trunk/fs/9p/v9fs.h | 29 +- trunk/fs/9p/v9fs_vfs.h | 3 +- trunk/fs/9p/vfs_file.c | 22 +- trunk/fs/9p/vfs_inode.c | 124 +- trunk/fs/9p/vfs_inode_dotl.c | 71 +- trunk/fs/affs/affs.h | 2 +- trunk/fs/affs/file.c | 8 +- trunk/fs/afs/afs_vl.h | 2 +- trunk/fs/afs/internal.h | 4 +- trunk/fs/afs/security.c | 6 +- trunk/fs/afs/write.c | 18 +- trunk/fs/attr.c | 6 + trunk/fs/bad_inode.c | 5 +- trunk/fs/binfmt_elf.c | 3 +- trunk/fs/binfmt_elf_fdpic.c | 3 +- trunk/fs/binfmt_misc.c | 3 +- trunk/fs/block_dev.c | 17 +- trunk/fs/btrfs/acl.c | 5 +- trunk/fs/btrfs/ctree.h | 9 +- trunk/fs/btrfs/disk-io.c | 15 +- trunk/fs/btrfs/file.c | 169 +- trunk/fs/btrfs/inode.c | 25 +- trunk/fs/btrfs/ioctl.c | 16 +- trunk/fs/cachefiles/bind.c | 2 + trunk/fs/ceph/caps.c | 6 +- trunk/fs/ceph/dir.c | 21 +- trunk/fs/ceph/file.c | 22 +- trunk/fs/ceph/inode.c | 6 +- trunk/fs/ceph/super.h | 5 +- trunk/fs/cifs/cifsfs.c | 11 +- trunk/fs/cifs/cifsfs.h | 4 +- trunk/fs/cifs/connect.c | 5 +- trunk/fs/cifs/dir.c | 14 +- trunk/fs/cifs/file.c | 18 +- trunk/fs/cifs/readdir.c | 2 +- trunk/fs/coda/coda_int.h | 2 +- trunk/fs/coda/coda_linux.h | 2 +- trunk/fs/coda/dir.c | 9 +- trunk/fs/coda/file.c | 8 +- trunk/fs/coda/pioctl.c | 4 +- trunk/fs/dcache.c | 262 +- trunk/fs/direct-io.c | 88 +- trunk/fs/ecryptfs/file.c | 7 +- trunk/fs/ecryptfs/inode.c | 37 +- trunk/fs/efs/namei.c | 7 +- trunk/fs/exec.c | 14 +- trunk/fs/exofs/file.c | 10 +- trunk/fs/exofs/namei.c | 7 +- trunk/fs/ext2/acl.c | 4 +- trunk/fs/ext2/acl.h | 2 +- trunk/fs/ext2/ext2.h | 3 +- trunk/fs/ext2/file.c | 4 +- trunk/fs/ext2/inode.c | 6 +- trunk/fs/ext2/namei.c | 14 +- trunk/fs/ext3/acl.c | 4 +- trunk/fs/ext3/acl.h | 2 +- trunk/fs/ext3/fsync.c | 18 +- trunk/fs/ext3/inode.c | 8 +- trunk/fs/ext3/namei.c | 14 +- trunk/fs/ext3/super.c | 2 - trunk/fs/ext4/acl.c | 4 +- trunk/fs/ext4/acl.h | 2 +- trunk/fs/ext4/ext4.h | 2 +- trunk/fs/ext4/file.c | 21 - trunk/fs/ext4/fsync.c | 38 +- trunk/fs/ext4/inode.c | 125 +- trunk/fs/ext4/namei.c | 14 +- trunk/fs/fat/fat.h | 4 +- trunk/fs/fat/file.c | 8 +- trunk/fs/fat/inode.c | 10 +- trunk/fs/fat/namei_msdos.c | 29 +- trunk/fs/fat/namei_vfat.c | 6 +- trunk/fs/fs-writeback.c | 28 +- trunk/fs/fuse/dir.c | 28 +- trunk/fs/fuse/file.c | 45 +- trunk/fs/fuse/fuse_i.h | 3 +- trunk/fs/generic_acl.c | 4 +- trunk/fs/gfs2/acl.c | 4 +- trunk/fs/gfs2/acl.h | 2 +- trunk/fs/gfs2/bmap.c | 2 - trunk/fs/gfs2/file.c | 19 +- trunk/fs/gfs2/inode.c | 35 +- trunk/fs/gfs2/inode.h | 2 +- trunk/fs/hfs/inode.c | 15 +- trunk/fs/hfsplus/hfsplus_fs.h | 3 +- trunk/fs/hfsplus/inode.c | 16 +- trunk/fs/hostfs/hostfs_kern.c | 21 +- trunk/fs/hpfs/dir.c | 4 - trunk/fs/hpfs/file.c | 7 +- trunk/fs/hpfs/hpfs_fn.h | 2 +- trunk/fs/hpfs/namei.c | 2 +- trunk/fs/hppfs/hppfs.c | 5 +- trunk/fs/inode.c | 129 +- trunk/fs/internal.h | 6 - trunk/fs/isofs/dir.c | 3 + trunk/fs/isofs/inode.c | 1 + trunk/fs/isofs/isofs.h | 1 + trunk/fs/isofs/namei.c | 13 +- trunk/fs/isofs/rock.c | 3 + trunk/fs/jffs2/acl.c | 4 +- trunk/fs/jffs2/acl.h | 2 +- trunk/fs/jffs2/dir.c | 9 +- trunk/fs/jffs2/file.c | 9 +- trunk/fs/jffs2/os-linux.h | 2 +- trunk/fs/jfs/acl.c | 4 +- trunk/fs/jfs/file.c | 11 +- trunk/fs/jfs/inode.c | 4 +- trunk/fs/jfs/jfs_acl.h | 2 +- trunk/fs/jfs/jfs_inode.h | 2 +- trunk/fs/jfs/namei.c | 49 +- trunk/fs/libfs.c | 26 +- trunk/fs/logfs/dir.c | 4 +- trunk/fs/logfs/file.c | 11 +- trunk/fs/logfs/logfs.h | 2 +- trunk/fs/minix/inode.c | 3 +- trunk/fs/namei.c | 462 +- trunk/fs/namespace.c | 4 +- trunk/fs/ncpfs/file.c | 4 +- trunk/fs/nfs/cache_lib.c | 9 +- trunk/fs/nfs/dir.c | 87 +- trunk/fs/nfs/direct.c | 4 +- trunk/fs/nfs/file.c | 18 +- trunk/fs/nfs/inode.c | 20 +- trunk/fs/nfs/nfs4_fs.h | 10 +- trunk/fs/nfs/nfs4proc.c | 70 +- trunk/fs/nfs/nfs4state.c | 12 +- trunk/fs/nfs/pagelist.c | 4 +- trunk/fs/nfs/read.c | 8 +- trunk/fs/nfs/super.c | 16 +- trunk/fs/nfs/write.c | 22 +- trunk/fs/nfsd/nfs4recover.c | 52 +- trunk/fs/nilfs2/file.c | 12 +- trunk/fs/nilfs2/inode.c | 10 +- trunk/fs/nilfs2/namei.c | 7 +- trunk/fs/nilfs2/nilfs.h | 4 +- trunk/fs/ntfs/dir.c | 10 +- trunk/fs/ntfs/file.c | 13 +- trunk/fs/ntfs/inode.c | 10 +- trunk/fs/ocfs2/acl.c | 4 +- trunk/fs/ocfs2/acl.h | 2 +- trunk/fs/ocfs2/aops.c | 10 +- trunk/fs/ocfs2/file.c | 41 +- trunk/fs/ocfs2/file.h | 2 +- trunk/fs/ocfs2/namei.c | 1 - trunk/fs/ocfs2/refcounttree.c | 49 +- trunk/fs/open.c | 2 +- trunk/fs/proc/base.c | 6 +- trunk/fs/proc/proc_sysctl.c | 4 +- trunk/fs/read_write.c | 44 +- trunk/fs/reiserfs/dir.c | 13 +- trunk/fs/reiserfs/file.c | 10 +- trunk/fs/reiserfs/inode.c | 8 +- trunk/fs/reiserfs/namei.c | 4 +- trunk/fs/reiserfs/super.c | 1 - trunk/fs/reiserfs/xattr.c | 25 +- trunk/fs/squashfs/namei.c | 10 +- trunk/fs/super.c | 176 +- trunk/fs/sync.c | 25 +- trunk/fs/sysfs/inode.c | 6 +- trunk/fs/sysfs/sysfs.h | 2 +- trunk/fs/ubifs/file.c | 21 +- trunk/fs/ubifs/ubifs.h | 2 +- trunk/fs/udf/file.c | 2 +- trunk/fs/ufs/namei.c | 2 + trunk/fs/xfs/linux-2.6/xfs_acl.c | 4 +- trunk/fs/xfs/linux-2.6/xfs_aops.c | 3 - trunk/fs/xfs/linux-2.6/xfs_file.c | 17 +- trunk/fs/xfs/linux-2.6/xfs_super.c | 27 +- trunk/fs/xfs/linux-2.6/xfs_sync.c | 71 +- trunk/fs/xfs/linux-2.6/xfs_sync.h | 5 +- trunk/fs/xfs/xfs_acl.h | 2 +- trunk/include/linux/anon_inodes.h | 2 - trunk/include/linux/atomic.h | 26 - trunk/include/linux/binfmts.h | 1 - trunk/include/linux/dcache.h | 8 +- trunk/include/linux/dw_apb_timer.h | 56 - trunk/include/linux/ext3_fs.h | 2 +- trunk/include/linux/fb.h | 3 +- trunk/include/linux/fs.h | 100 +- trunk/include/linux/generic_acl.h | 2 +- trunk/include/linux/irq.h | 5 + trunk/include/linux/iscsi_boot_sysfs.h | 16 +- trunk/include/linux/mm.h | 39 +- trunk/include/linux/mnt_namespace.h | 1 + trunk/include/linux/namei.h | 5 +- trunk/include/linux/nfs_fs.h | 6 +- trunk/include/linux/nsproxy.h | 1 - trunk/include/linux/pci_ids.h | 1 - trunk/include/linux/regmap.h | 82 - trunk/include/linux/reiserfs_xattr.h | 4 +- trunk/include/linux/rwsem.h | 10 + trunk/include/linux/security.h | 9 +- trunk/include/linux/seq_file.h | 1 - trunk/include/linux/shrinker.h | 42 - trunk/include/net/9p/9p.h | 193 +- trunk/include/net/9p/client.h | 12 +- trunk/include/net/9p/transport.h | 2 +- trunk/include/scsi/iscsi_proto.h | 18 +- trunk/include/scsi/libfc.h | 8 - trunk/include/scsi/libiscsi.h | 2 +- trunk/include/sound/rawmidi.h | 4 +- trunk/include/sound/soc-dai.h | 4 - trunk/include/sound/soc-dapm.h | 7 +- trunk/include/sound/soc.h | 59 +- trunk/include/trace/events/asoc.h | 45 - trunk/include/trace/events/vmscan.h | 77 - trunk/init/Kconfig | 2 - trunk/ipc/shm.c | 4 +- trunk/kernel/cgroup.c | 3 +- trunk/kernel/fork.c | 1 - trunk/kernel/nsproxy.c | 4 +- trunk/kernel/rwsem.c | 16 + trunk/mm/filemap.c | 3 + trunk/mm/madvise.c | 2 +- trunk/mm/rmap.c | 1 + trunk/mm/swapfile.c | 29 +- trunk/mm/truncate.c | 3 +- trunk/mm/vmscan.c | 71 +- trunk/net/9p/client.c | 155 +- trunk/net/9p/mod.c | 4 +- trunk/net/9p/protocol.c | 44 +- trunk/net/9p/trans_virtio.c | 4 +- trunk/net/sunrpc/clnt.c | 11 +- trunk/net/unix/af_unix.c | 38 +- trunk/security/capability.c | 2 +- trunk/security/security.c | 9 +- trunk/security/selinux/avc.c | 2 +- trunk/security/selinux/hooks.c | 3 +- trunk/security/smack/smack_lsm.c | 5 +- trunk/security/tomoyo/realpath.c | 2 +- trunk/sound/core/rawmidi.c | 45 +- trunk/sound/firewire/speakers.c | 2 +- trunk/sound/pci/ad1889.c | 4 +- trunk/sound/pci/ali5451/ali5451.c | 4 +- trunk/sound/pci/als300.c | 4 +- trunk/sound/pci/als4000.c | 2 +- trunk/sound/pci/asihpi/asihpi.c | 81 +- trunk/sound/pci/asihpi/hpi.h | 24 +- trunk/sound/pci/asihpi/hpi6000.c | 11 +- trunk/sound/pci/asihpi/hpi6205.c | 52 +- trunk/sound/pci/asihpi/hpi6205.h | 25 +- trunk/sound/pci/asihpi/hpi_internal.h | 155 +- trunk/sound/pci/asihpi/hpicmn.c | 17 +- trunk/sound/pci/asihpi/hpidspcd.c | 136 +- trunk/sound/pci/asihpi/hpidspcd.h | 72 +- trunk/sound/pci/asihpi/hpifunc.c | 86 +- trunk/sound/pci/asihpi/hpimsginit.c | 4 +- trunk/sound/pci/asihpi/hpimsgx.c | 6 +- trunk/sound/pci/asihpi/hpioctl.c | 10 +- trunk/sound/pci/asihpi/hpios.c | 8 + trunk/sound/pci/asihpi/hpios.h | 1 - trunk/sound/pci/atiixp.c | 4 +- trunk/sound/pci/atiixp_modem.c | 4 +- trunk/sound/pci/au88x0/au88x0.c | 4 +- trunk/sound/pci/aw2/aw2-alsa.c | 4 +- trunk/sound/pci/azt3328.c | 4 +- trunk/sound/pci/bt87x.c | 4 +- trunk/sound/pci/ca0106/ca0106_main.c | 4 +- trunk/sound/pci/cmipci.c | 4 +- trunk/sound/pci/cs4281.c | 4 +- trunk/sound/pci/cs46xx/cs46xx.c | 2 +- trunk/sound/pci/cs46xx/cs46xx_lib.c | 2 +- trunk/sound/pci/cs5530.c | 2 +- trunk/sound/pci/cs5535audio/cs5535audio.c | 4 +- trunk/sound/pci/ctxfi/ct20k2reg.h | 1 - trunk/sound/pci/ctxfi/ctatc.c | 107 +- trunk/sound/pci/ctxfi/ctatc.h | 8 +- trunk/sound/pci/ctxfi/ctdaio.c | 23 +- trunk/sound/pci/ctxfi/ctdaio.h | 1 - trunk/sound/pci/ctxfi/cthardware.h | 14 +- trunk/sound/pci/ctxfi/cthw20k1.c | 15 +- trunk/sound/pci/ctxfi/cthw20k2.c | 337 +- trunk/sound/pci/ctxfi/ctmixer.c | 145 +- trunk/sound/pci/ctxfi/xfi.c | 6 +- trunk/sound/pci/echoaudio/echoaudio.c | 6 +- trunk/sound/pci/emu10k1/emu10k1.c | 2 +- trunk/sound/pci/emu10k1/emu10k1_main.c | 2 +- trunk/sound/pci/emu10k1/emu10k1x.c | 4 +- trunk/sound/pci/ens1370.c | 4 +- trunk/sound/pci/es1938.c | 6 +- trunk/sound/pci/es1968.c | 68 +- trunk/sound/pci/fm801.c | 4 +- trunk/sound/pci/hda/Kconfig | 39 - trunk/sound/pci/hda/Makefile | 4 - trunk/sound/pci/hda/alc260_quirks.c | 1272 - trunk/sound/pci/hda/alc262_quirks.c | 1353 - trunk/sound/pci/hda/alc268_quirks.c | 636 - trunk/sound/pci/hda/alc269_quirks.c | 681 - trunk/sound/pci/hda/alc662_quirks.c | 1408 -- trunk/sound/pci/hda/alc680_quirks.c | 222 - trunk/sound/pci/hda/alc861_quirks.c | 725 - trunk/sound/pci/hda/alc861vd_quirks.c | 605 - trunk/sound/pci/hda/alc880_quirks.c | 1898 -- trunk/sound/pci/hda/alc882_quirks.c | 3755 --- trunk/sound/pci/hda/alc_quirks.c | 467 - trunk/sound/pci/hda/hda_codec.c | 363 +- trunk/sound/pci/hda/hda_codec.h | 30 +- trunk/sound/pci/hda/hda_eld.c | 46 +- trunk/sound/pci/hda/hda_intel.c | 80 +- trunk/sound/pci/hda/hda_local.h | 10 +- trunk/sound/pci/hda/hda_proc.c | 2 +- trunk/sound/pci/hda/patch_analog.c | 7 +- trunk/sound/pci/hda/patch_ca0110.c | 3 +- trunk/sound/pci/hda/patch_ca0132.c | 1097 - trunk/sound/pci/hda/patch_cirrus.c | 19 +- trunk/sound/pci/hda/patch_cmedia.c | 17 +- trunk/sound/pci/hda/patch_conexant.c | 71 +- trunk/sound/pci/hda/patch_hdmi.c | 704 +- trunk/sound/pci/hda/patch_realtek.c | 21020 +++++++++++++--- trunk/sound/pci/hda/patch_sigmatel.c | 31 +- trunk/sound/pci/hda/patch_via.c | 6573 +++-- trunk/sound/pci/ice1712/ice1712.c | 4 +- trunk/sound/pci/ice1712/ice1724.c | 4 +- trunk/sound/pci/intel8x0.c | 12 +- trunk/sound/pci/intel8x0m.c | 6 +- trunk/sound/pci/korg1212/korg1212.c | 4 +- trunk/sound/pci/lola/lola.c | 4 +- trunk/sound/pci/lola/lola.h | 2 +- trunk/sound/pci/lola/lola_mixer.c | 130 +- trunk/sound/pci/lx6464es/lx6464es.c | 25 +- trunk/sound/pci/lx6464es/lx6464es.h | 2 - trunk/sound/pci/lx6464es/lx_core.c | 14 +- trunk/sound/pci/lx6464es/lx_core.h | 2 +- trunk/sound/pci/maestro3.c | 75 +- trunk/sound/pci/mixart/mixart.c | 4 +- trunk/sound/pci/nm256/nm256.c | 4 +- trunk/sound/pci/oxygen/oxygen.c | 2 +- trunk/sound/pci/oxygen/oxygen_lib.c | 2 +- trunk/sound/pci/oxygen/oxygen_pcm.c | 6 + trunk/sound/pci/oxygen/virtuoso.c | 2 +- trunk/sound/pci/oxygen/xonar_pcm179x.c | 5 +- trunk/sound/pci/pcxhr/pcxhr.c | 4 +- trunk/sound/pci/riptide/riptide.c | 6 +- trunk/sound/pci/rme32.c | 4 +- trunk/sound/pci/rme96.c | 4 +- trunk/sound/pci/rme9652/hdsp.c | 4 +- trunk/sound/pci/rme9652/hdspm.c | 4 +- trunk/sound/pci/rme9652/rme9652.c | 4 +- trunk/sound/pci/sis7019.c | 6 +- trunk/sound/pci/sonicvibes.c | 4 +- trunk/sound/pci/trident/trident.c | 2 +- trunk/sound/pci/trident/trident_main.c | 2 +- trunk/sound/pci/via82xx.c | 4 +- trunk/sound/pci/via82xx_modem.c | 4 +- trunk/sound/pci/vx222/vx222.c | 4 +- trunk/sound/pci/ymfpci/ymfpci.c | 2 +- trunk/sound/pci/ymfpci/ymfpci_main.c | 2 +- trunk/sound/pcmcia/pdaudiocf/pdaudiocf.c | 2 +- trunk/sound/pcmcia/vx/vxpocket.c | 2 +- trunk/sound/soc/Makefile | 1 - trunk/sound/soc/atmel/atmel-pcm.c | 8 +- trunk/sound/soc/atmel/atmel-pcm.h | 2 +- trunk/sound/soc/atmel/atmel_ssc_dai.c | 6 +- trunk/sound/soc/atmel/sam9g20_wm8731.c | 1 - trunk/sound/soc/au1x/dbdma2.c | 7 +- trunk/sound/soc/blackfin/Kconfig | 27 +- trunk/sound/soc/blackfin/Makefile | 4 - trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c | 6 +- trunk/sound/soc/blackfin/bf5xx-i2s-pcm.c | 12 +- trunk/sound/soc/blackfin/bf5xx-tdm-pcm.c | 6 +- trunk/sound/soc/blackfin/bfin-eval-adau1701.c | 139 - trunk/sound/soc/blackfin/bfin-eval-adav80x.c | 173 - trunk/sound/soc/codecs/Kconfig | 22 +- trunk/sound/soc/codecs/Makefile | 10 - trunk/sound/soc/codecs/ad1836.c | 313 +- trunk/sound/soc/codecs/ad1836.h | 44 +- trunk/sound/soc/codecs/adau1701.c | 549 - trunk/sound/soc/codecs/adau1701.h | 17 - trunk/sound/soc/codecs/adav80x.c | 951 - trunk/sound/soc/codecs/adav80x.h | 35 - trunk/sound/soc/codecs/ak4641.c | 2 +- trunk/sound/soc/codecs/cs4270.c | 5 +- trunk/sound/soc/codecs/max98088.c | 2 + trunk/sound/soc/codecs/max98095.c | 10 +- trunk/sound/soc/codecs/sta32x.c | 917 - trunk/sound/soc/codecs/sta32x.h | 210 - trunk/sound/soc/codecs/tlv320aic3x.c | 34 +- trunk/sound/soc/codecs/twl6040.c | 4 +- trunk/sound/soc/codecs/wm8782.c | 80 - trunk/sound/soc/codecs/wm8900.c | 1 - trunk/sound/soc/codecs/wm8904.c | 1 - trunk/sound/soc/codecs/wm8915.c | 156 +- trunk/sound/soc/codecs/wm8940.c | 7 + trunk/sound/soc/codecs/wm8962.c | 132 +- trunk/sound/soc/codecs/wm8983.c | 1203 - trunk/sound/soc/codecs/wm8983.h | 1029 - trunk/sound/soc/codecs/wm8993.c | 3 +- trunk/sound/soc/codecs/wm8994.c | 148 +- trunk/sound/soc/codecs/wm8994.h | 3 - trunk/sound/soc/codecs/wm9081.c | 2 +- trunk/sound/soc/codecs/wm_hubs.c | 54 +- trunk/sound/soc/codecs/wm_hubs.h | 10 - trunk/sound/soc/davinci/davinci-pcm.c | 154 +- trunk/sound/soc/ep93xx/ep93xx-pcm.c | 6 +- trunk/sound/soc/fsl/fsl_dma.c | 8 +- trunk/sound/soc/fsl/fsl_ssi.c | 9 +- trunk/sound/soc/fsl/mpc5200_dma.c | 7 +- trunk/sound/soc/fsl/mpc8610_hpcd.c | 10 +- trunk/sound/soc/fsl/p1022_ds.c | 10 +- trunk/sound/soc/imx/imx-pcm-fiq.c | 8 +- trunk/sound/soc/imx/imx-ssi.c | 7 +- trunk/sound/soc/imx/imx-ssi.h | 3 +- trunk/sound/soc/jz4740/jz4740-pcm.c | 6 +- trunk/sound/soc/kirkwood/kirkwood-dma.c | 6 +- trunk/sound/soc/mid-x86/sst_platform.c | 5 +- trunk/sound/soc/nuc900/nuc900-ac97.c | 2 +- trunk/sound/soc/nuc900/nuc900-pcm.c | 7 +- trunk/sound/soc/omap/Kconfig | 11 - trunk/sound/soc/omap/Makefile | 4 - trunk/sound/soc/omap/ams-delta.c | 3 +- trunk/sound/soc/omap/omap-hdmi.c | 158 - trunk/sound/soc/omap/omap-hdmi.h | 36 - trunk/sound/soc/omap/omap-pcm.c | 6 +- trunk/sound/soc/omap/omap4-hdmi-card.c | 129 - trunk/sound/soc/pxa/pxa2xx-pcm.c | 5 +- trunk/sound/soc/s6000/s6000-pcm.c | 7 +- trunk/sound/soc/samsung/Kconfig | 16 +- trunk/sound/soc/samsung/Makefile | 4 - trunk/sound/soc/samsung/dma.c | 6 +- trunk/sound/soc/samsung/i2s-regs.h | 143 - trunk/sound/soc/samsung/i2s.c | 104 +- trunk/sound/soc/samsung/smdk_wm8994.c | 5 +- trunk/sound/soc/samsung/smdk_wm8994pcm.c | 176 - trunk/sound/soc/samsung/speyside.c | 61 +- trunk/sound/soc/samsung/speyside_wm8962.c | 264 - trunk/sound/soc/sh/dma-sh7760.c | 6 +- trunk/sound/soc/sh/fsi.c | 582 +- trunk/sound/soc/sh/siu_pcm.c | 5 +- trunk/sound/soc/soc-cache.c | 692 +- trunk/sound/soc/soc-core.c | 821 +- trunk/sound/soc/soc-dapm.c | 275 +- trunk/sound/soc/soc-io.c | 396 - trunk/sound/soc/soc-pcm.c | 639 - trunk/sound/soc/tegra/Kconfig | 9 - trunk/sound/soc/tegra/Makefile | 2 - trunk/sound/soc/tegra/tegra_i2s.c | 4 +- trunk/sound/soc/tegra/tegra_pcm.c | 6 +- trunk/sound/soc/tegra/tegra_spdif.c | 371 - trunk/sound/soc/tegra/tegra_spdif.h | 473 - trunk/sound/soc/tegra/tegra_wm8903.c | 2 +- trunk/sound/soc/txx9/txx9aclc.c | 5 +- trunk/sound/usb/card.c | 16 +- trunk/sound/usb/endpoint.c | 2 - trunk/sound/usb/misc/ua101.c | 2 +- trunk/sound/usb/quirks-table.h | 30 - trunk/sound/usb/quirks.c | 159 +- trunk/tools/perf/Makefile | 5 +- 656 files changed, 32028 insertions(+), 49491 deletions(-) delete mode 100644 trunk/Documentation/sound/alsa/HD-Audio-Controls.txt delete mode 100644 trunk/arch/blackfin/include/asm/auxvec.h delete mode 100644 trunk/arch/blackfin/include/asm/bitsperlong.h delete mode 100644 trunk/arch/blackfin/include/asm/bugs.h delete mode 100644 trunk/arch/blackfin/include/asm/cputime.h delete mode 100644 trunk/arch/blackfin/include/asm/current.h delete mode 100644 trunk/arch/blackfin/include/asm/device.h delete mode 100644 trunk/arch/blackfin/include/asm/div64.h delete mode 100644 trunk/arch/blackfin/include/asm/emergency-restart.h delete mode 100644 trunk/arch/blackfin/include/asm/errno.h delete mode 100644 trunk/arch/blackfin/include/asm/fb.h delete mode 100644 trunk/arch/blackfin/include/asm/futex.h delete mode 100644 trunk/arch/blackfin/include/asm/hw_irq.h delete mode 100644 trunk/arch/blackfin/include/asm/ioctl.h delete mode 100644 trunk/arch/blackfin/include/asm/ipcbuf.h delete mode 100644 trunk/arch/blackfin/include/asm/irq_regs.h delete mode 100644 trunk/arch/blackfin/include/asm/kdebug.h delete mode 100644 trunk/arch/blackfin/include/asm/kmap_types.h delete mode 100644 trunk/arch/blackfin/include/asm/local.h delete mode 100644 trunk/arch/blackfin/include/asm/local64.h delete mode 100644 trunk/arch/blackfin/include/asm/mman.h delete mode 100644 trunk/arch/blackfin/include/asm/msgbuf.h delete mode 100644 trunk/arch/blackfin/include/asm/param.h delete mode 100644 trunk/arch/blackfin/include/asm/percpu.h delete mode 100644 trunk/arch/blackfin/include/asm/pgalloc.h delete mode 100644 trunk/arch/blackfin/include/asm/resource.h delete mode 100644 trunk/arch/blackfin/include/asm/scatterlist.h delete mode 100644 trunk/arch/blackfin/include/asm/sembuf.h delete mode 100644 trunk/arch/blackfin/include/asm/serial.h delete mode 100644 trunk/arch/blackfin/include/asm/setup.h delete mode 100644 trunk/arch/blackfin/include/asm/shmbuf.h delete mode 100644 trunk/arch/blackfin/include/asm/shmparam.h delete mode 100644 trunk/arch/blackfin/include/asm/socket.h delete mode 100644 trunk/arch/blackfin/include/asm/sockios.h delete mode 100644 trunk/arch/blackfin/include/asm/statfs.h delete mode 100644 trunk/arch/blackfin/include/asm/termbits.h delete mode 100644 trunk/arch/blackfin/include/asm/termios.h delete mode 100644 trunk/arch/blackfin/include/asm/topology.h delete mode 100644 trunk/arch/blackfin/include/asm/types.h delete mode 100644 trunk/arch/blackfin/include/asm/ucontext.h delete mode 100644 trunk/arch/blackfin/include/asm/unaligned.h delete mode 100644 trunk/arch/blackfin/include/asm/user.h delete mode 100644 trunk/arch/blackfin/include/asm/xor.h delete mode 100644 trunk/drivers/base/regmap/Kconfig delete mode 100644 trunk/drivers/base/regmap/Makefile delete mode 100644 trunk/drivers/base/regmap/regmap-i2c.c delete mode 100644 trunk/drivers/base/regmap/regmap-spi.c delete mode 100644 trunk/drivers/base/regmap/regmap.c delete mode 100644 trunk/drivers/clocksource/dw_apb_timer.c delete mode 100644 trunk/drivers/scsi/bfa/bfad_bsg.c delete mode 100644 trunk/drivers/scsi/bfa/bfad_bsg.h create mode 100644 trunk/drivers/scsi/bfa/bfi_cbreg.h create mode 100644 trunk/drivers/scsi/bfa/bfi_ctreg.h delete mode 100644 trunk/drivers/scsi/bfa/bfi_reg.h delete mode 100644 trunk/include/linux/dw_apb_timer.h delete mode 100644 trunk/include/linux/regmap.h delete mode 100644 trunk/include/linux/shrinker.h delete mode 100644 trunk/sound/pci/hda/alc260_quirks.c delete mode 100644 trunk/sound/pci/hda/alc262_quirks.c delete mode 100644 trunk/sound/pci/hda/alc268_quirks.c delete mode 100644 trunk/sound/pci/hda/alc269_quirks.c delete mode 100644 trunk/sound/pci/hda/alc662_quirks.c delete mode 100644 trunk/sound/pci/hda/alc680_quirks.c delete mode 100644 trunk/sound/pci/hda/alc861_quirks.c delete mode 100644 trunk/sound/pci/hda/alc861vd_quirks.c delete mode 100644 trunk/sound/pci/hda/alc880_quirks.c delete mode 100644 trunk/sound/pci/hda/alc882_quirks.c delete mode 100644 trunk/sound/pci/hda/alc_quirks.c delete mode 100644 trunk/sound/pci/hda/patch_ca0132.c delete mode 100644 trunk/sound/soc/blackfin/bfin-eval-adau1701.c delete mode 100644 trunk/sound/soc/blackfin/bfin-eval-adav80x.c delete mode 100644 trunk/sound/soc/codecs/adau1701.c delete mode 100644 trunk/sound/soc/codecs/adau1701.h delete mode 100644 trunk/sound/soc/codecs/adav80x.c delete mode 100644 trunk/sound/soc/codecs/adav80x.h delete mode 100644 trunk/sound/soc/codecs/sta32x.c delete mode 100644 trunk/sound/soc/codecs/sta32x.h delete mode 100644 trunk/sound/soc/codecs/wm8782.c delete mode 100644 trunk/sound/soc/codecs/wm8983.c delete mode 100644 trunk/sound/soc/codecs/wm8983.h delete mode 100644 trunk/sound/soc/omap/omap-hdmi.c delete mode 100644 trunk/sound/soc/omap/omap-hdmi.h delete mode 100644 trunk/sound/soc/omap/omap4-hdmi-card.c delete mode 100644 trunk/sound/soc/samsung/i2s-regs.h delete mode 100644 trunk/sound/soc/samsung/smdk_wm8994pcm.c delete mode 100644 trunk/sound/soc/samsung/speyside_wm8962.c delete mode 100644 trunk/sound/soc/soc-io.c delete mode 100644 trunk/sound/soc/soc-pcm.c delete mode 100644 trunk/sound/soc/tegra/tegra_spdif.c delete mode 100644 trunk/sound/soc/tegra/tegra_spdif.h diff --git a/[refs] b/[refs] index de3454389a93..8d9b334acb19 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: f5fc87905ea075a0b14878086fd4fe38be128844 +refs/heads/master: c6cb13f9fef2e401d9fbb0709d088e7c50fe7aea diff --git a/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl b/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl index 598c22f3b3ac..58ced2346e67 100644 --- a/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl +++ b/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -1164,7 +1164,7 @@ } chip->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_mychip_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "My Chip", chip)) { printk(KERN_ERR "cannot grab irq %d\n", pci->irq); snd_mychip_free(chip); return -EBUSY; @@ -1197,7 +1197,7 @@ /* pci_driver definition */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "My Own Chip", .id_table = snd_mychip_ids, .probe = snd_mychip_probe, .remove = __devexit_p(snd_mychip_remove), @@ -1340,7 +1340,7 @@ irq, snd_mychip_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "My Chip", chip)) { printk(KERN_ERR "cannot grab irq %d\n", pci->irq); snd_mychip_free(chip); return -EBUSY; @@ -1616,7 +1616,7 @@ g1/tasks +# echo $$ > g1 The above steps create a new group g1 and move the current shell process (bash) into it. CPU time consumed by this bash and its children diff --git a/trunk/Documentation/cgroups/cpusets.txt b/trunk/Documentation/cgroups/cpusets.txt index 5c51ed406d1d..5b0d78e55ccc 100644 --- a/trunk/Documentation/cgroups/cpusets.txt +++ b/trunk/Documentation/cgroups/cpusets.txt @@ -180,7 +180,7 @@ files describing that cpuset: - cpuset.sched_load_balance flag: if set, load balance within CPUs on that cpuset - cpuset.sched_relax_domain_level: the searching range when migrating tasks -In addition, only the root cpuset has the following file: +In addition, the root cpuset only has the following file: - cpuset.memory_pressure_enabled flag: compute memory_pressure? New cpusets are created using the mkdir system call or shell diff --git a/trunk/Documentation/filesystems/Locking b/trunk/Documentation/filesystems/Locking index ca7e25292542..57d827d6071d 100644 --- a/trunk/Documentation/filesystems/Locking +++ b/trunk/Documentation/filesystems/Locking @@ -52,7 +52,7 @@ ata *); void (*put_link) (struct dentry *, struct nameidata *, void *); void (*truncate) (struct inode *); int (*permission) (struct inode *, int, unsigned int); - int (*check_acl)(struct inode *, int); + int (*check_acl)(struct inode *, int, unsigned int); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); @@ -412,7 +412,7 @@ prototypes: int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); - int (*fsync) (struct file *, loff_t start, loff_t end, int datasync); + int (*fsync) (struct file *, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); @@ -438,7 +438,9 @@ prototypes: locking rules: All may block except for ->setlease. - No VFS locks held on entry except for ->setlease. + No VFS locks held on entry except for ->fsync and ->setlease. + +->fsync() has i_mutex on inode. ->setlease has the file_list_lock held and must not sleep. diff --git a/trunk/Documentation/filesystems/porting b/trunk/Documentation/filesystems/porting index 7f8861d341ea..6e29954851a2 100644 --- a/trunk/Documentation/filesystems/porting +++ b/trunk/Documentation/filesystems/porting @@ -398,33 +398,12 @@ Currently you can only have FALLOC_FL_PUNCH_HOLE with FALLOC_FL_KEEP_SIZE set, so the i_size should not change when hole punching, even when puching the end of a file off. +-- +[mandatory] + -- [mandatory] ->get_sb() is gone. Switch to use of ->mount(). Typically it's just a matter of switching from calling get_sb_... to mount_... and changing the function type. If you were doing it manually, just switch from setting ->mnt_root to some pointer to returning that pointer. On errors return ERR_PTR(...). - --- -[mandatory] - ->permission(), generic_permission() and ->check_acl() have lost flags -argument; instead of passing IPERM_FLAG_RCU we add MAY_NOT_BLOCK into mask. - generic_permission() has also lost the check_acl argument; if you want -non-NULL to be used for that inode, put it into ->i_op->check_acl. - --- -[mandatory] - If you implement your own ->llseek() you must handle SEEK_HOLE and -SEEK_DATA. You can hanle this by returning -EINVAL, but it would be nicer to -support it in some way. The generic handler assumes that the entire file is -data and there is a virtual hole at the end of the file. So if the provided -offset is less than i_size and SEEK_DATA is specified, return the same offset. -If the above is true for the offset and you are given SEEK_HOLE, return the end -of the file. If the offset is i_size or greater return -ENXIO in either case. - -[mandatory] - If you have your own ->fsync() you must make sure to call -filemap_write_and_wait_range() so that all dirty pages are synced out properly. -You must also keep in mind that ->fsync() is not called with i_mutex held -anymore, so if you require i_mutex locking you must make sure to take it and -release it yourself. diff --git a/trunk/Documentation/filesystems/vfs.txt b/trunk/Documentation/filesystems/vfs.txt index eff6617c9a0f..88b9f5519af9 100644 --- a/trunk/Documentation/filesystems/vfs.txt +++ b/trunk/Documentation/filesystems/vfs.txt @@ -229,8 +229,6 @@ struct super_operations { ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); - int (*nr_cached_objects)(struct super_block *); - void (*free_cached_objects)(struct super_block *, int); }; All methods are called without any locks being held, unless otherwise @@ -303,26 +301,6 @@ or bottom half). quota_write: called by the VFS to write to filesystem quota file. - nr_cached_objects: called by the sb cache shrinking function for the - filesystem to return the number of freeable cached objects it contains. - Optional. - - free_cache_objects: called by the sb cache shrinking function for the - filesystem to scan the number of objects indicated to try to free them. - Optional, but any filesystem implementing this method needs to also - implement ->nr_cached_objects for it to be called correctly. - - We can't do anything with any errors that the filesystem might - encountered, hence the void return type. This will never be called if - the VM is trying to reclaim under GFP_NOFS conditions, hence this - method does not need to handle that situation itself. - - Implementations must include conditional reschedule calls inside any - scanning loop that is done. This allows the VFS to determine - appropriate scan batch sizes without having to worry about whether - implementations will cause holdoff problems due to large scan batch - sizes. - Whoever sets up the inode is responsible for filling in the "i_op" field. This is a pointer to a "struct inode_operations" which describes the methods that can be performed on individual inodes. @@ -355,8 +333,8 @@ struct inode_operations { void * (*follow_link) (struct dentry *, struct nameidata *); void (*put_link) (struct dentry *, struct nameidata *, void *); void (*truncate) (struct inode *); - int (*permission) (struct inode *, int); - int (*check_acl)(struct inode *, int); + int (*permission) (struct inode *, int, unsigned int); + int (*check_acl)(struct inode *, int, unsigned int); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); @@ -445,7 +423,7 @@ otherwise noted. permission: called by the VFS to check for access rights on a POSIX-like filesystem. - May be called in rcu-walk mode (mask & MAY_NOT_BLOCK). If in rcu-walk + May be called in rcu-walk mode (flags & IPERM_FLAG_RCU). If in rcu-walk mode, the filesystem must check the permission without blocking or storing to the inode. @@ -777,7 +755,7 @@ struct file_operations { int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); - int (*fsync) (struct file *, loff_t, loff_t, int datasync); + int (*fsync) (struct file *, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); diff --git a/trunk/Documentation/sound/alsa/HD-Audio-Controls.txt b/trunk/Documentation/sound/alsa/HD-Audio-Controls.txt deleted file mode 100644 index 1482035243e6..000000000000 --- a/trunk/Documentation/sound/alsa/HD-Audio-Controls.txt +++ /dev/null @@ -1,100 +0,0 @@ -This file explains the codec-specific mixer controls. - -Realtek codecs --------------- - -* Channel Mode - This is an enum control to change the surround-channel setup, - appears only when the surround channels are available. - It gives the number of channels to be used, "2ch", "4ch", "6ch", - and "8ch". According to the configuration, this also controls the - jack-retasking of multi-I/O jacks. - -* Auto-Mute Mode - This is an enum control to change the auto-mute behavior of the - headphone and line-out jacks. If built-in speakers and headphone - and/or line-out jacks are available on a machine, this controls - appears. - When there are only either headphones or line-out jacks, it gives - "Disabled" and "Enabled" state. When enabled, the speaker is muted - automatically when a jack is plugged. - - When both headphone and line-out jacks are present, it gives - "Disabled", "Speaker Only" and "Line-Out+Speaker". When - speaker-only is chosen, plugging into a headphone or a line-out jack - mutes the speakers, but not line-outs. When line-out+speaker is - selected, plugging to a headphone jack mutes both speakers and - line-outs. - - -IDT/Sigmatel codecs -------------------- - -* Analog Loopback - This control enables/disables the analog-loopback circuit. This - appears only when "loopback" is set to true in a codec hint - (see HD-Audio.txt). Note that on some codecs the analog-loopback - and the normal PCM playback are exclusive, i.e. when this is on, you - won't hear any PCM stream. - -* Swap Center/LFE - Swaps the center and LFE channel order. Normally, the left - corresponds to the center and the right to the LFE. When this is - ON, the left to the LFE and the right to the center. - -* Headphone as Line Out - When this control is ON, treat the headphone jacks as line-out - jacks. That is, the headphone won't auto-mute the other line-outs, - and no HP-amp is set to the pins. - -* Mic Jack Mode, Line Jack Mode, etc - These enum controls the direction and the bias of the input jack - pins. Depending on the jack type, it can set as "Mic In" and "Line - In", for determining the input bias, or it can be set to "Line Out" - when the pin is a multi-I/O jack for surround channels. - - -VIA codecs ----------- - -* Smart 5.1 - An enum control to re-task the multi-I/O jacks for surround outputs. - When it's ON, the corresponding input jacks (usually a line-in and a - mic-in) are switched as the surround and the CLFE output jacks. - -* Independent HP - When this enum control is enabled, the headphone output is routed - from an individual stream (the third PCM such as hw:0,2) instead of - the primary stream. In the case the headphone DAC is shared with a - side or a CLFE-channel DAC, the DAC is switched to the headphone - automatically. - -* Loopback Mixing - An enum control to determine whether the analog-loopback route is - enabled or not. When it's enabled, the analog-loopback is mixed to - the front-channel. Also, the same route is used for the headphone - and speaker outputs. As a side-effect, when this mode is set, the - individual volume controls will be no longer available for - headphones and speakers because there is only one DAC connected to a - mixer widget. - -* Dynamic Power-Control - This control determines whether the dynamic power-control per jack - detection is enabled or not. When enabled, the widgets power state - (D0/D3) are changed dynamically depending on the jack plugging - state for saving power consumptions. However, if your system - doesn't provide a proper jack-detection, this won't work; in such a - case, turn this control OFF. - -* Jack Detect - This control is provided only for VT1708 codec which gives no proper - unsolicited event per jack plug. When this is on, the driver polls - the jack detection so that the headphone auto-mute can work, while - turning this off would reduce the power consumption. - - -Conexant codecs ---------------- - -* Auto-Mute Mode - See Reatek codecs. diff --git a/trunk/Documentation/sysctl/kernel.txt b/trunk/Documentation/sysctl/kernel.txt index 1c7fb0a94e28..5e7cb39ad195 100644 --- a/trunk/Documentation/sysctl/kernel.txt +++ b/trunk/Documentation/sysctl/kernel.txt @@ -17,21 +17,23 @@ before actually making adjustments. Currently, these files might (depending on your configuration) show up in /proc/sys/kernel: - -- acct - acpi_video_flags -- auto_msgmni +- acct - bootloader_type [ X86 only ] - bootloader_version [ X86 only ] - callhome [ S390 only ] +- auto_msgmni - core_pattern - core_pipe_limit - core_uses_pid - ctrl-alt-del +- dentry-state - dmesg_restrict - domainname - hostname - hotplug +- java-appletviewer [ binfmt_java, obsolete ] +- java-interpreter [ binfmt_java, obsolete ] - kptr_restrict - kstack_depth_to_print [ X86 only ] - l2cr [ PPC only ] @@ -46,14 +48,10 @@ show up in /proc/sys/kernel: - overflowgid - overflowuid - panic -- panic_on_oops -- panic_on_unrecovered_nmi - pid_max - powersave-nap [ PPC only ] +- panic_on_unrecovered_nmi - printk -- printk_delay -- printk_ratelimit -- printk_ratelimit_burst - randomize_va_space - real-root-dev ==> Documentation/initrd.txt - reboot-cmd [ SPARC only ] @@ -64,7 +62,6 @@ show up in /proc/sys/kernel: - shmall - shmmax [ sysv ipc ] - shmmni -- softlockup_thresh - stop-a [ SPARC only ] - sysrq ==> Documentation/sysrq.txt - tainted @@ -74,6 +71,15 @@ show up in /proc/sys/kernel: ============================================================== +acpi_video_flags: + +flags + +See Doc*/kernel/power/video.txt, it allows mode of video boot to be +set during run time. + +============================================================== + acct: highwater lowwater frequency @@ -89,25 +95,6 @@ That is, suspend accounting if there left <= 2% free; resume it if we got >=4%; consider information about amount of free space valid for 30 seconds. -============================================================== - -acpi_video_flags: - -flags - -See Doc*/kernel/power/video.txt, it allows mode of video boot to be -set during run time. - -============================================================== - -auto_msgmni: - -Enables/Disables automatic recomputing of msgmni upon memory add/remove -or upon ipc namespace creation/removal (see the msgmni description -above). Echoing "1" into this file enables msgmni automatic recomputing. -Echoing "0" turns it off. auto_msgmni default value is 1. - - ============================================================== bootloader_type: @@ -185,24 +172,22 @@ core_pattern is used to specify a core dumpfile pattern name. core_pipe_limit: -This sysctl is only applicable when core_pattern is configured to pipe -core files to a user space helper (when the first character of -core_pattern is a '|', see above). When collecting cores via a pipe -to an application, it is occasionally useful for the collecting -application to gather data about the crashing process from its -/proc/pid directory. In order to do this safely, the kernel must wait -for the collecting process to exit, so as not to remove the crashing -processes proc files prematurely. This in turn creates the -possibility that a misbehaving userspace collecting process can block -the reaping of a crashed process simply by never exiting. This sysctl -defends against that. It defines how many concurrent crashing -processes may be piped to user space applications in parallel. If -this value is exceeded, then those crashing processes above that value -are noted via the kernel log and their cores are skipped. 0 is a -special value, indicating that unlimited processes may be captured in -parallel, but that no waiting will take place (i.e. the collecting -process is not guaranteed access to /proc//). This -value defaults to 0. +This sysctl is only applicable when core_pattern is configured to pipe core +files to a user space helper (when the first character of core_pattern is a '|', +see above). When collecting cores via a pipe to an application, it is +occasionally useful for the collecting application to gather data about the +crashing process from its /proc/pid directory. In order to do this safely, the +kernel must wait for the collecting process to exit, so as not to remove the +crashing processes proc files prematurely. This in turn creates the possibility +that a misbehaving userspace collecting process can block the reaping of a +crashed process simply by never exiting. This sysctl defends against that. It +defines how many concurrent crashing processes may be piped to user space +applications in parallel. If this value is exceeded, then those crashing +processes above that value are noted via the kernel log and their cores are +skipped. 0 is a special value, indicating that unlimited processes may be +captured in parallel, but that no waiting will take place (i.e. the collecting +process is not guaranteed access to /proc//). This value defaults +to 0. ============================================================== @@ -233,14 +218,14 @@ to decide what to do with it. dmesg_restrict: -This toggle indicates whether unprivileged users are prevented -from using dmesg(8) to view messages from the kernel's log buffer. -When dmesg_restrict is set to (0) there are no restrictions. When +This toggle indicates whether unprivileged users are prevented from using +dmesg(8) to view messages from the kernel's log buffer. When +dmesg_restrict is set to (0) there are no restrictions. When dmesg_restrict is set set to (1), users must have CAP_SYSLOG to use dmesg(8). -The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the -default value of dmesg_restrict. +The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default +value of dmesg_restrict. ============================================================== @@ -271,6 +256,13 @@ Default value is "/sbin/hotplug". ============================================================== +l2cr: (PPC only) + +This flag controls the L2 cache of G3 processor boards. If +0, the cache is disabled. Enabled if nonzero. + +============================================================== + kptr_restrict: This toggle indicates whether restrictions are placed on @@ -291,13 +283,6 @@ kernel stack. ============================================================== -l2cr: (PPC only) - -This flag controls the L2 cache of G3 processor boards. If -0, the cache is disabled. Enabled if nonzero. - -============================================================== - modules_disabled: A toggle value indicating if modules are allowed to be loaded @@ -308,21 +293,6 @@ to false. ============================================================== -nmi_watchdog: - -Enables/Disables the NMI watchdog on x86 systems. When the value is -non-zero the NMI watchdog is enabled and will continuously test all -online cpus to determine whether or not they are still functioning -properly. Currently, passing "nmi_watchdog=" parameter at boot time is -required for this function to work. - -If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel -parameter), the NMI watchdog shares registers with oprofile. By -disabling the NMI watchdog, oprofile may have more registers to -utilize. - -============================================================== - osrelease, ostype & version: # cat osrelease @@ -342,10 +312,10 @@ The only way to tune these values is to rebuild the kernel :-) overflowgid & overflowuid: -if your architecture did not always support 32-bit UIDs (i.e. arm, -i386, m68k, sh, and sparc32), a fixed UID and GID will be returned to -applications that use the old 16-bit UID/GID system calls, if the -actual UID or GID would exceed 65535. +if your architecture did not always support 32-bit UIDs (i.e. arm, i386, +m68k, sh, and sparc32), a fixed UID and GID will be returned to +applications that use the old 16-bit UID/GID system calls, if the actual +UID or GID would exceed 65535. These sysctls allow you to change the value of the fixed UID and GID. The default is 65534. @@ -354,22 +324,9 @@ The default is 65534. panic: -The value in this file represents the number of seconds the kernel -waits before rebooting on a panic. When you use the software watchdog, -the recommended setting is 60. - -============================================================== - -panic_on_unrecovered_nmi: - -The default Linux behaviour on an NMI of either memory or unknown is -to continue operation. For many environments such as scientific -computing it is preferable that the box is taken out and the error -dealt with than an uncorrected parity/ECC error get propagated. - -A small number of systems do generate NMI's for bizarre random reasons -such as power management so the default is off. That sysctl works like -the existing panic controls already in that directory. +The value in this file represents the number of seconds the +kernel waits before rebooting on a panic. When you use the +software watchdog, the recommended setting is 60. ============================================================== @@ -419,14 +376,6 @@ the different loglevels. ============================================================== -printk_delay: - -Delay each printk message in printk_delay milliseconds - -Value from 0 - 10000 is allowed. - -============================================================== - printk_ratelimit: Some warning messages are rate limited. printk_ratelimit specifies @@ -446,7 +395,15 @@ send before ratelimiting kicks in. ============================================================== -randomize_va_space: +printk_delay: + +Delay each printk message in printk_delay milliseconds + +Value from 0 - 10000 is allowed. + +============================================================== + +randomize-va-space: This option can be used to select the type of process address space randomization that is used in the system, for architectures @@ -509,11 +466,11 @@ are doing anyway :) ============================================================== -shmmax: +shmmax: This value can be used to query and set the run time limit on the maximum shared memory segment size that can be created. -Shared memory segments up to 1Gb are now supported in the +Shared memory segments up to 1Gb are now supported in the kernel. This value defaults to SHMMAX. ============================================================== @@ -527,7 +484,7 @@ tunable to zero will disable the softlockup detection altogether. ============================================================== -tainted: +tainted: Non-zero if the kernel has been tainted. Numeric values, which can be ORed together: @@ -552,11 +509,49 @@ can be ORed together: ============================================================== +auto_msgmni: + +Enables/Disables automatic recomputing of msgmni upon memory add/remove or +upon ipc namespace creation/removal (see the msgmni description above). +Echoing "1" into this file enables msgmni automatic recomputing. +Echoing "0" turns it off. +auto_msgmni default value is 1. + +============================================================== + +nmi_watchdog: + +Enables/Disables the NMI watchdog on x86 systems. When the value is non-zero +the NMI watchdog is enabled and will continuously test all online cpus to +determine whether or not they are still functioning properly. Currently, +passing "nmi_watchdog=" parameter at boot time is required for this function +to work. + +If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel parameter), the +NMI watchdog shares registers with oprofile. By disabling the NMI watchdog, +oprofile may have more registers to utilize. + +============================================================== + unknown_nmi_panic: -The value in this file affects behavior of handling NMI. When the -value is non-zero, unknown NMI is trapped and then panic occurs. At -that time, kernel debugging information is displayed on console. +The value in this file affects behavior of handling NMI. When the value is +non-zero, unknown NMI is trapped and then panic occurs. At that time, kernel +debugging information is displayed on console. + +NMI switch that most IA32 servers have fires unknown NMI up, for example. +If a system hangs up, try pressing the NMI switch. + +============================================================== + +panic_on_unrecovered_nmi: + +The default Linux behaviour on an NMI of either memory or unknown is to continue +operation. For many environments such as scientific computing it is preferable +that the box is taken out and the error dealt with than an uncorrected +parity/ECC error get propogated. + +A small number of systems do generate NMI's for bizarre random reasons such as +power management so the default is off. That sysctl works like the existing +panic controls already in that directory. -NMI switch that most IA32 servers have fires unknown NMI up, for -example. If a system hangs up, try pressing the NMI switch. diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 63524a09ca86..41ec646d8a98 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -534,8 +534,6 @@ L: device-drivers-devel@blackfin.uclinux.org L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://wiki.analog.com/ S: Supported -F: sound/soc/codecs/adau* -F: sound/soc/codecs/adav* F: sound/soc/codecs/ad1* F: sound/soc/codecs/ssm* @@ -1553,12 +1551,6 @@ L: linux-wireless@vger.kernel.org S: Supported F: drivers/staging/brcm80211/ -BROADCOM BNX2FC 10 GIGABIT FCOE DRIVER -M: Bhanu Prakash Gollapudi -L: linux-scsi@vger.kernel.org -S: Supported -F: drivers/scsi/bnx2fc/ - BROCADE BFA FC SCSI DRIVER M: Jing Huang L: linux-scsi@vger.kernel.org @@ -1781,8 +1773,7 @@ F: include/linux/clk.h CISCO FCOE HBA DRIVER M: Abhijeet Joglekar -M: Venkata Siva Vijayendra Bhamidipati -M: Brian Uchino +M: Joe Eykholt L: linux-scsi@vger.kernel.org S: Supported F: drivers/scsi/fnic/ @@ -5327,13 +5318,6 @@ L: reiserfs-devel@vger.kernel.org S: Supported F: fs/reiserfs/ -REGISTER MAP ABSTRACTION -M: Mark Brown -T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git -S: Supported -F: drivers/base/regmap/ -F: include/linux/regmap.h - RFKILL M: Johannes Berg L: linux-wireless@vger.kernel.org diff --git a/trunk/arch/arm/mach-tegra/clock.c b/trunk/arch/arm/mach-tegra/clock.c index f8d41ffc0ca9..e028320ab423 100644 --- a/trunk/arch/arm/mach-tegra/clock.c +++ b/trunk/arch/arm/mach-tegra/clock.c @@ -585,7 +585,7 @@ static const struct file_operations possible_parents_fops = { static int clk_debugfs_register_one(struct clk *c) { - struct dentry *d; + struct dentry *d, *child, *child_tmp; d = debugfs_create_dir(c->name, clk_debugfs_root); if (!d) @@ -614,7 +614,10 @@ static int clk_debugfs_register_one(struct clk *c) return 0; err_out: - debugfs_remove_recursive(c->dent); + d = c->dent; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(c->dent); return -ENOMEM; } diff --git a/trunk/arch/arm/mach-ux500/clock.c b/trunk/arch/arm/mach-ux500/clock.c index 7d107be63eb4..32ce90840ee1 100644 --- a/trunk/arch/arm/mach-ux500/clock.c +++ b/trunk/arch/arm/mach-ux500/clock.c @@ -635,13 +635,16 @@ static const struct file_operations set_rate_fops = { static struct dentry *clk_debugfs_register_dir(struct clk *c, struct dentry *p_dentry) { - struct dentry *d, *clk_d; - const char *p = c->name; + struct dentry *d, *clk_d, *child, *child_tmp; + char s[255]; + char *p = s; - if (!p) - p = "BUG"; + if (c->name == NULL) + p += sprintf(p, "BUG"); + else + p += sprintf(p, "%s", c->name); - clk_d = debugfs_create_dir(p, p_dentry); + clk_d = debugfs_create_dir(s, p_dentry); if (!clk_d) return NULL; @@ -663,10 +666,24 @@ static struct dentry *clk_debugfs_register_dir(struct clk *c, return clk_d; err_out: - debugfs_remove_recursive(clk_d); + d = clk_d; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(clk_d); return NULL; } +static void clk_debugfs_remove_dir(struct dentry *cdentry) +{ + struct dentry *d, *child, *child_tmp; + + d = cdentry; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(cdentry); + return ; +} + static int clk_debugfs_register_one(struct clk *c) { struct clk *pa = c->parent_periph; @@ -683,7 +700,7 @@ static int clk_debugfs_register_one(struct clk *c) c->dent_bus = clk_debugfs_register_dir(c, bpa->dent_bus ? bpa->dent_bus : bpa->dent); if ((!c->dent_bus) && (c->dent)) { - debugfs_remove_recursive(c->dent); + clk_debugfs_remove_dir(c->dent); c->dent = NULL; return -ENOMEM; } diff --git a/trunk/arch/arm/plat-omap/clock.c b/trunk/arch/arm/plat-omap/clock.c index 964704f40bbe..c9122dd6ee8d 100644 --- a/trunk/arch/arm/plat-omap/clock.c +++ b/trunk/arch/arm/plat-omap/clock.c @@ -480,10 +480,13 @@ static struct dentry *clk_debugfs_root; static int clk_debugfs_register_one(struct clk *c) { int err; - struct dentry *d; + struct dentry *d, *child, *child_tmp; struct clk *pa = c->parent; + char s[255]; + char *p = s; - d = debugfs_create_dir(c->name, pa ? pa->dent : clk_debugfs_root); + p += sprintf(p, "%s", c->name); + d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root); if (!d) return -ENOMEM; c->dent = d; @@ -506,7 +509,10 @@ static int clk_debugfs_register_one(struct clk *c) return 0; err_out: - debugfs_remove_recursive(c->dent); + d = c->dent; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(c->dent); return err; } diff --git a/trunk/arch/arm/plat-samsung/clock.c b/trunk/arch/arm/plat-samsung/clock.c index 0c9f95d98561..772892826ffc 100644 --- a/trunk/arch/arm/plat-samsung/clock.c +++ b/trunk/arch/arm/plat-samsung/clock.c @@ -458,7 +458,7 @@ static struct dentry *clk_debugfs_root; static int clk_debugfs_register_one(struct clk *c) { int err; - struct dentry *d; + struct dentry *d, *child, *child_tmp; struct clk *pa = c->parent; char s[255]; char *p = s; @@ -488,7 +488,10 @@ static int clk_debugfs_register_one(struct clk *c) return 0; err_out: - debugfs_remove_recursive(c->dent); + d = c->dent; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(c->dent); return err; } diff --git a/trunk/arch/arm/plat-spear/clock.c b/trunk/arch/arm/plat-spear/clock.c index 67dd00381ea6..6fa474cb398e 100644 --- a/trunk/arch/arm/plat-spear/clock.c +++ b/trunk/arch/arm/plat-spear/clock.c @@ -916,7 +916,7 @@ static struct dentry *clk_debugfs_root; static int clk_debugfs_register_one(struct clk *c) { int err; - struct dentry *d; + struct dentry *d, *child; struct clk *pa = c->pclk; char s[255]; char *p = s; @@ -951,7 +951,10 @@ static int clk_debugfs_register_one(struct clk *c) return 0; err_out: - debugfs_remove_recursive(c->dent); + d = c->dent; + list_for_each_entry(child, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(c->dent); return err; } diff --git a/trunk/arch/blackfin/include/asm/Kbuild b/trunk/arch/blackfin/include/asm/Kbuild index 9e7c5379d3ff..7a075eaf6041 100644 --- a/trunk/arch/blackfin/include/asm/Kbuild +++ b/trunk/arch/blackfin/include/asm/Kbuild @@ -1,5 +1,48 @@ include include/asm-generic/Kbuild.asm +generic-y += auxvec.h +generic-y += bitsperlong.h +generic-y += bugs.h +generic-y += cputime.h +generic-y += current.h +generic-y += device.h +generic-y += div64.h +generic-y += emergency-restart.h +generic-y += errno.h +generic-y += fb.h +generic-y += futex.h +generic-y += hw_irq.h +generic-y += ioctl.h +generic-y += ipcbuf.h +generic-y += irq_regs.h +generic-y += kdebug.h +generic-y += kmap_types.h +generic-y += local64.h +generic-y += local.h +generic-y += mman.h +generic-y += msgbuf.h +generic-y += param.h +generic-y += percpu.h +generic-y += pgalloc.h +generic-y += resource.h +generic-y += scatterlist.h +generic-y += sembuf.h +generic-y += serial.h +generic-y += setup.h +generic-y += shmbuf.h +generic-y += shmparam.h +generic-y += socket.h +generic-y += sockios.h +generic-y += statfs.h +generic-y += termbits.h +generic-y += termios.h +generic-y += topology.h +generic-y += types.h +generic-y += ucontext.h +generic-y += unaligned.h +generic-y += user.h +generic-y += xor.h + header-y += bfin_sport.h header-y += cachectl.h header-y += fixed_code.h diff --git a/trunk/arch/blackfin/include/asm/auxvec.h b/trunk/arch/blackfin/include/asm/auxvec.h deleted file mode 100644 index 41fa68b71287..000000000000 --- a/trunk/arch/blackfin/include/asm/auxvec.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/bitsperlong.h b/trunk/arch/blackfin/include/asm/bitsperlong.h deleted file mode 100644 index 6dc0bb0c13b2..000000000000 --- a/trunk/arch/blackfin/include/asm/bitsperlong.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/bugs.h b/trunk/arch/blackfin/include/asm/bugs.h deleted file mode 100644 index 61791e1ad9f5..000000000000 --- a/trunk/arch/blackfin/include/asm/bugs.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/cputime.h b/trunk/arch/blackfin/include/asm/cputime.h deleted file mode 100644 index 6d68ad7e0ea3..000000000000 --- a/trunk/arch/blackfin/include/asm/cputime.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/current.h b/trunk/arch/blackfin/include/asm/current.h deleted file mode 100644 index 4c51401b5537..000000000000 --- a/trunk/arch/blackfin/include/asm/current.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/device.h b/trunk/arch/blackfin/include/asm/device.h deleted file mode 100644 index f0a4c256403b..000000000000 --- a/trunk/arch/blackfin/include/asm/device.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/div64.h b/trunk/arch/blackfin/include/asm/div64.h deleted file mode 100644 index 6cd978cefb28..000000000000 --- a/trunk/arch/blackfin/include/asm/div64.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/emergency-restart.h b/trunk/arch/blackfin/include/asm/emergency-restart.h deleted file mode 100644 index 3711bd9d50bd..000000000000 --- a/trunk/arch/blackfin/include/asm/emergency-restart.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/errno.h b/trunk/arch/blackfin/include/asm/errno.h deleted file mode 100644 index 4c82b503d92f..000000000000 --- a/trunk/arch/blackfin/include/asm/errno.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/fb.h b/trunk/arch/blackfin/include/asm/fb.h deleted file mode 100644 index 3a4988e8df45..000000000000 --- a/trunk/arch/blackfin/include/asm/fb.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/futex.h b/trunk/arch/blackfin/include/asm/futex.h deleted file mode 100644 index 0b745828f42b..000000000000 --- a/trunk/arch/blackfin/include/asm/futex.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/hw_irq.h b/trunk/arch/blackfin/include/asm/hw_irq.h deleted file mode 100644 index 1f5ef7da0045..000000000000 --- a/trunk/arch/blackfin/include/asm/hw_irq.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/ioctl.h b/trunk/arch/blackfin/include/asm/ioctl.h deleted file mode 100644 index b279fe06dfe5..000000000000 --- a/trunk/arch/blackfin/include/asm/ioctl.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/ipcbuf.h b/trunk/arch/blackfin/include/asm/ipcbuf.h deleted file mode 100644 index 84c7e51cb6d0..000000000000 --- a/trunk/arch/blackfin/include/asm/ipcbuf.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/irq_regs.h b/trunk/arch/blackfin/include/asm/irq_regs.h deleted file mode 100644 index 3dd9c0b70270..000000000000 --- a/trunk/arch/blackfin/include/asm/irq_regs.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/kdebug.h b/trunk/arch/blackfin/include/asm/kdebug.h deleted file mode 100644 index 6ece1b037665..000000000000 --- a/trunk/arch/blackfin/include/asm/kdebug.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/kmap_types.h b/trunk/arch/blackfin/include/asm/kmap_types.h deleted file mode 100644 index 3575c64af42a..000000000000 --- a/trunk/arch/blackfin/include/asm/kmap_types.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/local.h b/trunk/arch/blackfin/include/asm/local.h deleted file mode 100644 index c11c530f74d0..000000000000 --- a/trunk/arch/blackfin/include/asm/local.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/local64.h b/trunk/arch/blackfin/include/asm/local64.h deleted file mode 100644 index 36c93b5cc239..000000000000 --- a/trunk/arch/blackfin/include/asm/local64.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/mman.h b/trunk/arch/blackfin/include/asm/mman.h deleted file mode 100644 index 8eebf89f5ab1..000000000000 --- a/trunk/arch/blackfin/include/asm/mman.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/msgbuf.h b/trunk/arch/blackfin/include/asm/msgbuf.h deleted file mode 100644 index 809134c644a6..000000000000 --- a/trunk/arch/blackfin/include/asm/msgbuf.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/param.h b/trunk/arch/blackfin/include/asm/param.h deleted file mode 100644 index 965d45427975..000000000000 --- a/trunk/arch/blackfin/include/asm/param.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/percpu.h b/trunk/arch/blackfin/include/asm/percpu.h deleted file mode 100644 index 06a959d67234..000000000000 --- a/trunk/arch/blackfin/include/asm/percpu.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/pgalloc.h b/trunk/arch/blackfin/include/asm/pgalloc.h deleted file mode 100644 index f261cb7dda06..000000000000 --- a/trunk/arch/blackfin/include/asm/pgalloc.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/resource.h b/trunk/arch/blackfin/include/asm/resource.h deleted file mode 100644 index 04bc4db8921b..000000000000 --- a/trunk/arch/blackfin/include/asm/resource.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/scatterlist.h b/trunk/arch/blackfin/include/asm/scatterlist.h deleted file mode 100644 index d177a1588958..000000000000 --- a/trunk/arch/blackfin/include/asm/scatterlist.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _BLACKFIN_SCATTERLIST_H -#define _BLACKFIN_SCATTERLIST_H - -#include - -#endif /* !(_BLACKFIN_SCATTERLIST_H) */ diff --git a/trunk/arch/blackfin/include/asm/sembuf.h b/trunk/arch/blackfin/include/asm/sembuf.h deleted file mode 100644 index 7673b83cfef7..000000000000 --- a/trunk/arch/blackfin/include/asm/sembuf.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/serial.h b/trunk/arch/blackfin/include/asm/serial.h deleted file mode 100644 index a0cb0caff152..000000000000 --- a/trunk/arch/blackfin/include/asm/serial.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/setup.h b/trunk/arch/blackfin/include/asm/setup.h deleted file mode 100644 index 552df83f1a49..000000000000 --- a/trunk/arch/blackfin/include/asm/setup.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/shmbuf.h b/trunk/arch/blackfin/include/asm/shmbuf.h deleted file mode 100644 index 83c05fc2de38..000000000000 --- a/trunk/arch/blackfin/include/asm/shmbuf.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/shmparam.h b/trunk/arch/blackfin/include/asm/shmparam.h deleted file mode 100644 index 93f30deb95d0..000000000000 --- a/trunk/arch/blackfin/include/asm/shmparam.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/socket.h b/trunk/arch/blackfin/include/asm/socket.h deleted file mode 100644 index 6b71384b9d8b..000000000000 --- a/trunk/arch/blackfin/include/asm/socket.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/sockios.h b/trunk/arch/blackfin/include/asm/sockios.h deleted file mode 100644 index def6d4746ee7..000000000000 --- a/trunk/arch/blackfin/include/asm/sockios.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/statfs.h b/trunk/arch/blackfin/include/asm/statfs.h deleted file mode 100644 index 0b91fe198c20..000000000000 --- a/trunk/arch/blackfin/include/asm/statfs.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/termbits.h b/trunk/arch/blackfin/include/asm/termbits.h deleted file mode 100644 index 3935b106de79..000000000000 --- a/trunk/arch/blackfin/include/asm/termbits.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/termios.h b/trunk/arch/blackfin/include/asm/termios.h deleted file mode 100644 index 280d78a9d966..000000000000 --- a/trunk/arch/blackfin/include/asm/termios.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/topology.h b/trunk/arch/blackfin/include/asm/topology.h deleted file mode 100644 index 5428f333a02c..000000000000 --- a/trunk/arch/blackfin/include/asm/topology.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/types.h b/trunk/arch/blackfin/include/asm/types.h deleted file mode 100644 index b9e79bc580dd..000000000000 --- a/trunk/arch/blackfin/include/asm/types.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/ucontext.h b/trunk/arch/blackfin/include/asm/ucontext.h deleted file mode 100644 index 9bc07b9f30fb..000000000000 --- a/trunk/arch/blackfin/include/asm/ucontext.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/unaligned.h b/trunk/arch/blackfin/include/asm/unaligned.h deleted file mode 100644 index 6cecbbb2111f..000000000000 --- a/trunk/arch/blackfin/include/asm/unaligned.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/user.h b/trunk/arch/blackfin/include/asm/user.h deleted file mode 100644 index 4792a60831e4..000000000000 --- a/trunk/arch/blackfin/include/asm/user.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/blackfin/include/asm/xor.h b/trunk/arch/blackfin/include/asm/xor.h deleted file mode 100644 index c82eb12a5b18..000000000000 --- a/trunk/arch/blackfin/include/asm/xor.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/trunk/arch/ia64/kvm/Kconfig b/trunk/arch/ia64/kvm/Kconfig index 9806e55f91be..fa4d1e59deb0 100644 --- a/trunk/arch/ia64/kvm/Kconfig +++ b/trunk/arch/ia64/kvm/Kconfig @@ -49,5 +49,6 @@ config KVM_INTEL extensions. source drivers/vhost/Kconfig +source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/mips/Kconfig b/trunk/arch/mips/Kconfig index 177cdaf83564..6cb60adb7b30 100644 --- a/trunk/arch/mips/Kconfig +++ b/trunk/arch/mips/Kconfig @@ -2493,4 +2493,20 @@ source "security/Kconfig" source "crypto/Kconfig" +menuconfig VIRTUALIZATION + bool "Virtualization" + default n + ---help--- + Say Y here to get to see options for using your Linux host to run other + operating systems inside virtual machines (guests). + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if VIRTUALIZATION + +source drivers/virtio/Kconfig + +endif # VIRTUALIZATION + source "lib/Kconfig" diff --git a/trunk/arch/powerpc/kvm/Kconfig b/trunk/arch/powerpc/kvm/Kconfig index 105b6918b23e..b7baff78f90c 100644 --- a/trunk/arch/powerpc/kvm/Kconfig +++ b/trunk/arch/powerpc/kvm/Kconfig @@ -99,5 +99,6 @@ config KVM_E500 If unsure, say N. source drivers/vhost/Kconfig +source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/powerpc/platforms/cell/spufs/file.c b/trunk/arch/powerpc/platforms/cell/spufs/file.c index fb59c46e9e9e..3c7c3f82d842 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/file.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/file.c @@ -1850,16 +1850,9 @@ static int spufs_mfc_flush(struct file *file, fl_owner_t id) return ret; } -static int spufs_mfc_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int spufs_mfc_fsync(struct file *file, int datasync) { - struct inode *inode = file->f_path.dentry->d_inode; - int err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (!err) { - mutex_lock(&inode->i_mutex); - err = spufs_mfc_flush(file, NULL); - mutex_unlock(&inode->i_mutex); - } - return err; + return spufs_mfc_flush(file, NULL); } static int spufs_mfc_fasync(int fd, struct file *file, int on) diff --git a/trunk/arch/powerpc/platforms/cell/spufs/inode.c b/trunk/arch/powerpc/platforms/cell/spufs/inode.c index e481f6b9a789..856e9c398068 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/inode.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/inode.c @@ -611,14 +611,15 @@ static int spufs_create_gang(struct inode *inode, static struct file_system_type spufs_type; -long spufs_create(struct path *path, struct dentry *dentry, - unsigned int flags, mode_t mode, struct file *filp) +long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, + struct file *filp) { + struct dentry *dentry; int ret; ret = -EINVAL; /* check if we are on spufs */ - if (path->dentry->d_sb->s_type != &spufs_type) + if (nd->path.dentry->d_sb->s_type != &spufs_type) goto out; /* don't accept undefined flags */ @@ -626,27 +627,33 @@ long spufs_create(struct path *path, struct dentry *dentry, goto out; /* only threads can be underneath a gang */ - if (path->dentry != path->dentry->d_sb->s_root) { + if (nd->path.dentry != nd->path.dentry->d_sb->s_root) { if ((flags & SPU_CREATE_GANG) || - !SPUFS_I(path->dentry->d_inode)->i_gang) + !SPUFS_I(nd->path.dentry->d_inode)->i_gang) goto out; } + dentry = lookup_create(nd, 1); + ret = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out_dir; + mode &= ~current_umask(); if (flags & SPU_CREATE_GANG) - ret = spufs_create_gang(path->dentry->d_inode, - dentry, path->mnt, mode); + ret = spufs_create_gang(nd->path.dentry->d_inode, + dentry, nd->path.mnt, mode); else - ret = spufs_create_context(path->dentry->d_inode, - dentry, path->mnt, flags, mode, + ret = spufs_create_context(nd->path.dentry->d_inode, + dentry, nd->path.mnt, flags, mode, filp); if (ret >= 0) - fsnotify_mkdir(path->dentry->d_inode, dentry); + fsnotify_mkdir(nd->path.dentry->d_inode, dentry); return ret; +out_dir: + mutex_unlock(&nd->path.dentry->d_inode->i_mutex); out: - mutex_unlock(&path->dentry->d_inode->i_mutex); return ret; } diff --git a/trunk/arch/powerpc/platforms/cell/spufs/spufs.h b/trunk/arch/powerpc/platforms/cell/spufs/spufs.h index 099245f230b2..c448bac65518 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/trunk/arch/powerpc/platforms/cell/spufs/spufs.h @@ -248,7 +248,7 @@ extern const struct spufs_tree_descr spufs_dir_debug_contents[]; /* system call implementation */ extern struct spufs_calls spufs_calls; long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); -long spufs_create(struct path *nd, struct dentry *dentry, unsigned int flags, +long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, struct file *filp); /* ELF coredump callbacks for writing SPU ELF notes */ extern int spufs_coredump_extra_notes_size(void); diff --git a/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c b/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c index 609e016e92d0..a3d2ce54ea2e 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -62,17 +62,21 @@ static long do_spu_run(struct file *filp, static long do_spu_create(const char __user *pathname, unsigned int flags, mode_t mode, struct file *neighbor) { - struct path path; - struct dentry *dentry; + char *tmp; int ret; - dentry = user_path_create(AT_FDCWD, pathname, &path, 1); - ret = PTR_ERR(dentry); - if (!IS_ERR(dentry)) { - ret = spufs_create(&path, dentry, flags, mode, neighbor); - mutex_unlock(&path.dentry->d_inode->i_mutex); - dput(dentry); - path_put(&path); + tmp = getname(pathname); + ret = PTR_ERR(tmp); + if (!IS_ERR(tmp)) { + struct nameidata nd; + + ret = kern_path_parent(tmp, &nd); + if (!ret) { + nd.flags |= LOOKUP_OPEN | LOOKUP_CREATE; + ret = spufs_create(&nd, flags, mode, neighbor); + path_put(&nd.path); + } + putname(tmp); } return ret; diff --git a/trunk/arch/s390/kvm/Kconfig b/trunk/arch/s390/kvm/Kconfig index a21634173a66..f66a1bdbb61d 100644 --- a/trunk/arch/s390/kvm/Kconfig +++ b/trunk/arch/s390/kvm/Kconfig @@ -37,5 +37,6 @@ config KVM # OK, it's a little counter-intuitive to do this, but it puts it neatly under # the virtualization menu. source drivers/vhost/Kconfig +source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/sh/Kconfig b/trunk/arch/sh/Kconfig index 748ff1920068..bbdeb48bbf8e 100644 --- a/trunk/arch/sh/Kconfig +++ b/trunk/arch/sh/Kconfig @@ -897,4 +897,20 @@ source "security/Kconfig" source "crypto/Kconfig" +menuconfig VIRTUALIZATION + bool "Virtualization" + default n + ---help--- + Say Y here to get to see options for using your Linux host to run other + operating systems inside virtual machines (guests). + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if VIRTUALIZATION + +source drivers/virtio/Kconfig + +endif # VIRTUALIZATION + source "lib/Kconfig" diff --git a/trunk/arch/tile/kvm/Kconfig b/trunk/arch/tile/kvm/Kconfig index 669fcdba31ea..b88f9c047781 100644 --- a/trunk/arch/tile/kvm/Kconfig +++ b/trunk/arch/tile/kvm/Kconfig @@ -33,5 +33,6 @@ config KVM If unsure, say N. source drivers/vhost/Kconfig +source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/um/sys-i386/Makefile b/trunk/arch/um/sys-i386/Makefile index 87b659dadf3f..15587ed9a361 100644 --- a/trunk/arch/um/sys-i386/Makefile +++ b/trunk/arch/um/sys-i386/Makefile @@ -8,8 +8,7 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ obj-$(CONFIG_BINFMT_ELF) += elfcore.o -subarch-obj-y = lib/string_32.o -subarch-obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += lib/rwsem.o +subarch-obj-y = lib/rwsem.o lib/string_32.o subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o subarch-obj-$(CONFIG_MODULES) += kernel/module.o diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig index b2127544fbe7..5f60ea190d5b 100644 --- a/trunk/arch/x86/Kconfig +++ b/trunk/arch/x86/Kconfig @@ -390,21 +390,12 @@ config X86_INTEL_CE This option compiles in support for the CE4100 SOC for settop boxes and media devices. -config X86_INTEL_MID - bool "Intel MID platform support" - depends on X86_32 - depends on X86_EXTENDED_PLATFORM - ---help--- - Select to build a kernel capable of supporting Intel MID platform - systems which do not have the PCI legacy interfaces (Moorestown, - Medfield). If you are building for a PC class system say N here. - -if X86_INTEL_MID - config X86_MRST bool "Moorestown MID platform" depends on PCI depends on PCI_GOANY + depends on X86_32 + depends on X86_EXTENDED_PLATFORM depends on X86_IO_APIC select APB_TIMER select I2C @@ -419,8 +410,6 @@ config X86_MRST nor standard legacy replacement devices/features. e.g. Moorestown does not contain i8259, i8254, HPET, legacy BIOS, most of the io ports. -endif - config X86_RDC321X bool "RDC R-321x SoC" depends on X86_32 @@ -634,7 +623,6 @@ config HPET_EMULATE_RTC config APB_TIMER def_bool y if MRST prompt "Langwell APB Timer Support" if X86_MRST - select DW_APB_TIMER help APB timer is the replacement for 8254, HPET on X86 MID platforms. The APBT provides a stable time base on SMP diff --git a/trunk/arch/x86/Kconfig.cpu b/trunk/arch/x86/Kconfig.cpu index e3ca7e0d858c..6a7cfdf8ff69 100644 --- a/trunk/arch/x86/Kconfig.cpu +++ b/trunk/arch/x86/Kconfig.cpu @@ -312,9 +312,6 @@ config X86_CMPXCHG config CMPXCHG_LOCAL def_bool X86_64 || (X86_32 && !M386) -config CMPXCHG_DOUBLE - def_bool y - config X86_L1_CACHE_SHIFT int default "7" if MPENTIUM4 || MPSC diff --git a/trunk/arch/x86/boot/Makefile b/trunk/arch/x86/boot/Makefile index 95365a82b6a0..f7cb086b4add 100644 --- a/trunk/arch/x86/boot/Makefile +++ b/trunk/arch/x86/boot/Makefile @@ -9,6 +9,12 @@ # Changed by many, many contributors over the years. # +# ROOT_DEV specifies the default root-device when making the image. +# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case +# the default of FLOPPY is used by 'build'. + +ROOT_DEV := CURRENT + # If you want to preset the SVGA mode, uncomment the next line and # set SVGA_MODE to whatever number you want. # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. @@ -69,7 +75,8 @@ GCOV_PROFILE := n $(obj)/bzImage: asflags-y := $(SVGA_MODE) quiet_cmd_image = BUILD $@ -cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin > $@ +cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \ + $(ROOT_DEV) > $@ $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE $(call if_changed,image) diff --git a/trunk/arch/x86/boot/tools/build.c b/trunk/arch/x86/boot/tools/build.c index fdc60a0b3c20..ee3a4ea923ac 100644 --- a/trunk/arch/x86/boot/tools/build.c +++ b/trunk/arch/x86/boot/tools/build.c @@ -130,7 +130,7 @@ static void die(const char * str, ...) static void usage(void) { - die("Usage: build setup system [> image]"); + die("Usage: build setup system [rootdev] [> image]"); } int main(int argc, char ** argv) @@ -138,14 +138,39 @@ int main(int argc, char ** argv) unsigned int i, sz, setup_sectors; int c; u32 sys_size; + u8 major_root, minor_root; struct stat sb; FILE *file; int fd; void *kernel; u32 crc = 0xffffffffUL; - if (argc != 3) + if ((argc < 3) || (argc > 4)) usage(); + if (argc > 3) { + if (!strcmp(argv[3], "CURRENT")) { + if (stat("/", &sb)) { + perror("/"); + die("Couldn't stat /"); + } + major_root = major(sb.st_dev); + minor_root = minor(sb.st_dev); + } else if (strcmp(argv[3], "FLOPPY")) { + if (stat(argv[3], &sb)) { + perror(argv[3]); + die("Couldn't stat root device."); + } + major_root = major(sb.st_rdev); + minor_root = minor(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); /* Copy the setup code */ file = fopen(argv[1], "r"); @@ -168,8 +193,8 @@ int main(int argc, char ** argv) memset(buf+c, 0, i-c); /* Set the default root device */ - buf[508] = DEFAULT_MINOR_ROOT; - buf[509] = DEFAULT_MAJOR_ROOT; + buf[508] = minor_root; + buf[509] = major_root; fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i); diff --git a/trunk/arch/x86/include/asm/apb_timer.h b/trunk/arch/x86/include/asm/apb_timer.h index 0acbac299e49..082cf8184935 100644 --- a/trunk/arch/x86/include/asm/apb_timer.h +++ b/trunk/arch/x86/include/asm/apb_timer.h @@ -18,6 +18,24 @@ #ifdef CONFIG_APB_TIMER +/* Langwell DW APB timer registers */ +#define APBTMR_N_LOAD_COUNT 0x00 +#define APBTMR_N_CURRENT_VALUE 0x04 +#define APBTMR_N_CONTROL 0x08 +#define APBTMR_N_EOI 0x0c +#define APBTMR_N_INT_STATUS 0x10 + +#define APBTMRS_INT_STATUS 0xa0 +#define APBTMRS_EOI 0xa4 +#define APBTMRS_RAW_INT_STATUS 0xa8 +#define APBTMRS_COMP_VERSION 0xac +#define APBTMRS_REG_SIZE 0x14 + +/* register bits */ +#define APBTMR_CONTROL_ENABLE (1<<0) +#define APBTMR_CONTROL_MODE_PERIODIC (1<<1) /*1: periodic 0:free running */ +#define APBTMR_CONTROL_INT (1<<2) + /* default memory mapped register base */ #define LNW_SCU_ADDR 0xFF100000 #define LNW_EXT_TIMER_OFFSET 0x1B800 @@ -25,8 +43,8 @@ #define LNW_EXT_TIMER_PGOFFSET 0x800 /* APBT clock speed range from PCLK to fabric base, 25-100MHz */ -#define APBT_MAX_FREQ 50000000 -#define APBT_MIN_FREQ 1000000 +#define APBT_MAX_FREQ 50 +#define APBT_MIN_FREQ 1 #define APBT_MMAP_SIZE 1024 #define APBT_DEV_USED 1 diff --git a/trunk/arch/x86/include/asm/cmpxchg_32.h b/trunk/arch/x86/include/asm/cmpxchg_32.h index 3deb7250624c..284a6e8f7ce1 100644 --- a/trunk/arch/x86/include/asm/cmpxchg_32.h +++ b/trunk/arch/x86/include/asm/cmpxchg_32.h @@ -280,52 +280,4 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old, #endif -#define cmpxchg8b(ptr, o1, o2, n1, n2) \ -({ \ - char __ret; \ - __typeof__(o2) __dummy; \ - __typeof__(*(ptr)) __old1 = (o1); \ - __typeof__(o2) __old2 = (o2); \ - __typeof__(*(ptr)) __new1 = (n1); \ - __typeof__(o2) __new2 = (n2); \ - asm volatile(LOCK_PREFIX "cmpxchg8b %2; setz %1" \ - : "=d"(__dummy), "=a" (__ret), "+m" (*ptr)\ - : "a" (__old1), "d"(__old2), \ - "b" (__new1), "c" (__new2) \ - : "memory"); \ - __ret; }) - - -#define cmpxchg8b_local(ptr, o1, o2, n1, n2) \ -({ \ - char __ret; \ - __typeof__(o2) __dummy; \ - __typeof__(*(ptr)) __old1 = (o1); \ - __typeof__(o2) __old2 = (o2); \ - __typeof__(*(ptr)) __new1 = (n1); \ - __typeof__(o2) __new2 = (n2); \ - asm volatile("cmpxchg8b %2; setz %1" \ - : "=d"(__dummy), "=a"(__ret), "+m" (*ptr)\ - : "a" (__old), "d"(__old2), \ - "b" (__new1), "c" (__new2), \ - : "memory"); \ - __ret; }) - - -#define cmpxchg_double(ptr, o1, o2, n1, n2) \ -({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ - VM_BUG_ON((unsigned long)(ptr) % 8); \ - cmpxchg8b((ptr), (o1), (o2), (n1), (n2)); \ -}) - -#define cmpxchg_double_local(ptr, o1, o2, n1, n2) \ -({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ - VM_BUG_ON((unsigned long)(ptr) % 8); \ - cmpxchg16b_local((ptr), (o1), (o2), (n1), (n2)); \ -}) - -#define system_has_cmpxchg_double() cpu_has_cx8 - #endif /* _ASM_X86_CMPXCHG_32_H */ diff --git a/trunk/arch/x86/include/asm/cmpxchg_64.h b/trunk/arch/x86/include/asm/cmpxchg_64.h index 7cf5c0a24434..423ae58aa020 100644 --- a/trunk/arch/x86/include/asm/cmpxchg_64.h +++ b/trunk/arch/x86/include/asm/cmpxchg_64.h @@ -151,49 +151,4 @@ extern void __cmpxchg_wrong_size(void); cmpxchg_local((ptr), (o), (n)); \ }) -#define cmpxchg16b(ptr, o1, o2, n1, n2) \ -({ \ - char __ret; \ - __typeof__(o2) __junk; \ - __typeof__(*(ptr)) __old1 = (o1); \ - __typeof__(o2) __old2 = (o2); \ - __typeof__(*(ptr)) __new1 = (n1); \ - __typeof__(o2) __new2 = (n2); \ - asm volatile(LOCK_PREFIX "cmpxchg16b %2;setz %1" \ - : "=d"(__junk), "=a"(__ret), "+m" (*ptr) \ - : "b"(__new1), "c"(__new2), \ - "a"(__old1), "d"(__old2)); \ - __ret; }) - - -#define cmpxchg16b_local(ptr, o1, o2, n1, n2) \ -({ \ - char __ret; \ - __typeof__(o2) __junk; \ - __typeof__(*(ptr)) __old1 = (o1); \ - __typeof__(o2) __old2 = (o2); \ - __typeof__(*(ptr)) __new1 = (n1); \ - __typeof__(o2) __new2 = (n2); \ - asm volatile("cmpxchg16b %2;setz %1" \ - : "=d"(__junk), "=a"(__ret), "+m" (*ptr) \ - : "b"(__new1), "c"(__new2), \ - "a"(__old1), "d"(__old2)); \ - __ret; }) - -#define cmpxchg_double(ptr, o1, o2, n1, n2) \ -({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ - VM_BUG_ON((unsigned long)(ptr) % 16); \ - cmpxchg16b((ptr), (o1), (o2), (n1), (n2)); \ -}) - -#define cmpxchg_double_local(ptr, o1, o2, n1, n2) \ -({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ - VM_BUG_ON((unsigned long)(ptr) % 16); \ - cmpxchg16b_local((ptr), (o1), (o2), (n1), (n2)); \ -}) - -#define system_has_cmpxchg_double() cpu_has_cx16 - #endif /* _ASM_X86_CMPXCHG_64_H */ diff --git a/trunk/arch/x86/include/asm/cpufeature.h b/trunk/arch/x86/include/asm/cpufeature.h index 4258aac99a6e..9929b35929ff 100644 --- a/trunk/arch/x86/include/asm/cpufeature.h +++ b/trunk/arch/x86/include/asm/cpufeature.h @@ -288,8 +288,6 @@ extern const char * const x86_power_flags[32]; #define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR) #define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ) #define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE) -#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8) -#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16) #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64) # define cpu_has_invlpg 1 diff --git a/trunk/arch/x86/kernel/apb_timer.c b/trunk/arch/x86/kernel/apb_timer.c index afdc3f756dea..2b6630d75e17 100644 --- a/trunk/arch/x86/kernel/apb_timer.c +++ b/trunk/arch/x86/kernel/apb_timer.c @@ -27,12 +27,15 @@ * timer, but by default APB timer has higher rating than local APIC timers. */ +#include +#include #include -#include #include #include +#include #include #include +#include #include #include #include @@ -43,46 +46,75 @@ #include #include +#define APBT_MASK CLOCKSOURCE_MASK(32) +#define APBT_SHIFT 22 #define APBT_CLOCKEVENT_RATING 110 #define APBT_CLOCKSOURCE_RATING 250 +#define APBT_MIN_DELTA_USEC 200 +#define EVT_TO_APBT_DEV(evt) container_of(evt, struct apbt_dev, evt) #define APBT_CLOCKEVENT0_NUM (0) +#define APBT_CLOCKEVENT1_NUM (1) #define APBT_CLOCKSOURCE_NUM (2) -static phys_addr_t apbt_address; +static unsigned long apbt_address; static int apb_timer_block_enabled; static void __iomem *apbt_virt_address; +static int phy_cs_timer_id; /* * Common DW APB timer info */ -static unsigned long apbt_freq; +static uint64_t apbt_freq; + +static void apbt_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt); +static int apbt_next_event(unsigned long delta, + struct clock_event_device *evt); +static cycle_t apbt_read_clocksource(struct clocksource *cs); +static void apbt_restart_clocksource(struct clocksource *cs); struct apbt_dev { - struct dw_apb_clock_event_device *timer; - unsigned int num; - int cpu; - unsigned int irq; - char name[10]; + struct clock_event_device evt; + unsigned int num; + int cpu; + unsigned int irq; + unsigned int tick; + unsigned int count; + unsigned int flags; + char name[10]; }; -static struct dw_apb_clocksource *clocksource_apbt; - -static inline void __iomem *adev_virt_addr(struct apbt_dev *adev) -{ - return apbt_virt_address + adev->num * APBTMRS_REG_SIZE; -} - static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); #ifdef CONFIG_SMP static unsigned int apbt_num_timers_used; +static struct apbt_dev *apbt_devs; #endif +static inline unsigned long apbt_readl_reg(unsigned long a) +{ + return readl(apbt_virt_address + a); +} + +static inline void apbt_writel_reg(unsigned long d, unsigned long a) +{ + writel(d, apbt_virt_address + a); +} + +static inline unsigned long apbt_readl(int n, unsigned long a) +{ + return readl(apbt_virt_address + a + n * APBTMRS_REG_SIZE); +} + +static inline void apbt_writel(int n, unsigned long d, unsigned long a) +{ + writel(d, apbt_virt_address + a + n * APBTMRS_REG_SIZE); +} + static inline void apbt_set_mapping(void) { struct sfi_timer_table_entry *mtmr; - int phy_cs_timer_id = 0; if (apbt_virt_address) { pr_debug("APBT base already mapped\n"); @@ -94,18 +126,21 @@ static inline void apbt_set_mapping(void) APBT_CLOCKEVENT0_NUM); return; } - apbt_address = (phys_addr_t)mtmr->phys_addr; + apbt_address = (unsigned long)mtmr->phys_addr; if (!apbt_address) { printk(KERN_WARNING "No timer base from SFI, use default\n"); apbt_address = APBT_DEFAULT_BASE; } apbt_virt_address = ioremap_nocache(apbt_address, APBT_MMAP_SIZE); - if (!apbt_virt_address) { - pr_debug("Failed mapping APBT phy address at %lu\n",\ - (unsigned long)apbt_address); + if (apbt_virt_address) { + pr_debug("Mapped APBT physical addr %p at virtual addr %p\n",\ + (void *)apbt_address, (void *)apbt_virt_address); + } else { + pr_debug("Failed mapping APBT phy address at %p\n",\ + (void *)apbt_address); goto panic_noapbt; } - apbt_freq = mtmr->freq_hz; + apbt_freq = mtmr->freq_hz / USEC_PER_SEC; sfi_free_mtmr(mtmr); /* Now figure out the physical timer id for clocksource device */ @@ -114,14 +149,9 @@ static inline void apbt_set_mapping(void) goto panic_noapbt; /* Now figure out the physical timer id */ - pr_debug("Use timer %d for clocksource\n", - (int)(mtmr->phys_addr & 0xff) / APBTMRS_REG_SIZE); - phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) / - APBTMRS_REG_SIZE; - - clocksource_apbt = dw_apb_clocksource_init(APBT_CLOCKSOURCE_RATING, - "apbt0", apbt_virt_address + phy_cs_timer_id * - APBTMRS_REG_SIZE, apbt_freq); + phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) + / APBTMRS_REG_SIZE; + pr_debug("Use timer %d for clocksource\n", phy_cs_timer_id); return; panic_noapbt: @@ -143,6 +173,82 @@ static inline int is_apbt_capable(void) return apbt_virt_address ? 1 : 0; } +static struct clocksource clocksource_apbt = { + .name = "apbt", + .rating = APBT_CLOCKSOURCE_RATING, + .read = apbt_read_clocksource, + .mask = APBT_MASK, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .resume = apbt_restart_clocksource, +}; + +/* boot APB clock event device */ +static struct clock_event_device apbt_clockevent = { + .name = "apbt0", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = apbt_set_mode, + .set_next_event = apbt_next_event, + .shift = APBT_SHIFT, + .irq = 0, + .rating = APBT_CLOCKEVENT_RATING, +}; + +/* + * start count down from 0xffff_ffff. this is done by toggling the enable bit + * then load initial load count to ~0. + */ +static void apbt_start_counter(int n) +{ + unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); + + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(n, ctrl, APBTMR_N_CONTROL); + apbt_writel(n, ~0, APBTMR_N_LOAD_COUNT); + /* enable, mask interrupt */ + ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; + ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); + apbt_writel(n, ctrl, APBTMR_N_CONTROL); + /* read it once to get cached counter value initialized */ + apbt_read_clocksource(&clocksource_apbt); +} + +static irqreturn_t apbt_interrupt_handler(int irq, void *data) +{ + struct apbt_dev *dev = (struct apbt_dev *)data; + struct clock_event_device *aevt = &dev->evt; + + if (!aevt->event_handler) { + printk(KERN_INFO "Spurious APBT timer interrupt on %d\n", + dev->num); + return IRQ_NONE; + } + aevt->event_handler(aevt); + return IRQ_HANDLED; +} + +static void apbt_restart_clocksource(struct clocksource *cs) +{ + apbt_start_counter(phy_cs_timer_id); +} + +static void apbt_enable_int(int n) +{ + unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); + /* clear pending intr */ + apbt_readl(n, APBTMR_N_EOI); + ctrl &= ~APBTMR_CONTROL_INT; + apbt_writel(n, ctrl, APBTMR_N_CONTROL); +} + +static void apbt_disable_int(int n) +{ + unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); + + ctrl |= APBTMR_CONTROL_INT; + apbt_writel(n, ctrl, APBTMR_N_CONTROL); +} + + static int __init apbt_clockevent_register(void) { struct sfi_timer_table_entry *mtmr; @@ -155,21 +261,45 @@ static int __init apbt_clockevent_register(void) return -ENODEV; } + /* + * We need to calculate the scaled math multiplication factor for + * nanosecond to apbt tick conversion. + * mult = (nsec/cycle)*2^APBT_SHIFT + */ + apbt_clockevent.mult = div_sc((unsigned long) mtmr->freq_hz + , NSEC_PER_SEC, APBT_SHIFT); + + /* Calculate the min / max delta */ + apbt_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, + &apbt_clockevent); + apbt_clockevent.min_delta_ns = clockevent_delta2ns( + APBT_MIN_DELTA_USEC*apbt_freq, + &apbt_clockevent); + /* + * Start apbt with the boot cpu mask and make it + * global if not used for per cpu timer. + */ + apbt_clockevent.cpumask = cpumask_of(smp_processor_id()); adev->num = smp_processor_id(); - adev->timer = dw_apb_clockevent_init(smp_processor_id(), "apbt0", - mrst_timer_options == MRST_TIMER_LAPIC_APBT ? - APBT_CLOCKEVENT_RATING - 100 : APBT_CLOCKEVENT_RATING, - adev_virt_addr(adev), 0, apbt_freq); - /* Firmware does EOI handling for us. */ - adev->timer->eoi = NULL; + memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device)); if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) { - global_clock_event = &adev->timer->ced; + adev->evt.rating = APBT_CLOCKEVENT_RATING - 100; + global_clock_event = &adev->evt; printk(KERN_DEBUG "%s clockevent registered as global\n", global_clock_event->name); } - dw_apb_clockevent_register(adev->timer); + if (request_irq(apbt_clockevent.irq, apbt_interrupt_handler, + IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, + apbt_clockevent.name, adev)) { + printk(KERN_ERR "Failed request IRQ for APBT%d\n", + apbt_clockevent.irq); + } + + clockevents_register_device(&adev->evt); + /* Start APBT 0 interrupts */ + apbt_enable_int(APBT_CLOCKEVENT0_NUM); sfi_free_mtmr(mtmr); return 0; @@ -187,34 +317,52 @@ static void apbt_setup_irq(struct apbt_dev *adev) irq_set_affinity(adev->irq, cpumask_of(adev->cpu)); /* APB timer irqs are set up as mp_irqs, timer is edge type */ __irq_set_handler(adev->irq, handle_edge_irq, 0, "edge"); + + if (system_state == SYSTEM_BOOTING) { + if (request_irq(adev->irq, apbt_interrupt_handler, + IRQF_TIMER | IRQF_DISABLED | + IRQF_NOBALANCING, + adev->name, adev)) { + printk(KERN_ERR "Failed request IRQ for APBT%d\n", + adev->num); + } + } else + enable_irq(adev->irq); } /* Should be called with per cpu */ void apbt_setup_secondary_clock(void) { struct apbt_dev *adev; + struct clock_event_device *aevt; int cpu; /* Don't register boot CPU clockevent */ cpu = smp_processor_id(); if (!cpu) return; + /* + * We need to calculate the scaled math multiplication factor for + * nanosecond to apbt tick conversion. + * mult = (nsec/cycle)*2^APBT_SHIFT + */ + printk(KERN_INFO "Init per CPU clockevent %d\n", cpu); + adev = &per_cpu(cpu_apbt_dev, cpu); + aevt = &adev->evt; - adev = &__get_cpu_var(cpu_apbt_dev); - if (!adev->timer) { - adev->timer = dw_apb_clockevent_init(cpu, adev->name, - APBT_CLOCKEVENT_RATING, adev_virt_addr(adev), - adev->irq, apbt_freq); - adev->timer->eoi = NULL; - } else { - dw_apb_clockevent_resume(adev->timer); - } + memcpy(aevt, &apbt_clockevent, sizeof(*aevt)); + aevt->cpumask = cpumask_of(cpu); + aevt->name = adev->name; + aevt->mode = CLOCK_EVT_MODE_UNUSED; - printk(KERN_INFO "Registering CPU %d clockevent device %s, cpu %08x\n", - cpu, adev->name, adev->cpu); + printk(KERN_INFO "Registering CPU %d clockevent device %s, mask %08x\n", + cpu, aevt->name, *(u32 *)aevt->cpumask); apbt_setup_irq(adev); - dw_apb_clockevent_register(adev->timer); + + clockevents_register_device(aevt); + + apbt_enable_int(cpu); return; } @@ -237,12 +385,13 @@ static int apbt_cpuhp_notify(struct notifier_block *n, switch (action & 0xf) { case CPU_DEAD: - dw_apb_clockevent_pause(adev->timer); + disable_irq(adev->irq); + apbt_disable_int(cpu); if (system_state == SYSTEM_RUNNING) { pr_debug("skipping APBT CPU %lu offline\n", cpu); } else if (adev) { pr_debug("APBT clockevent for cpu %lu offline\n", cpu); - dw_apb_clockevent_stop(adev->timer); + free_irq(adev->irq, adev); } break; default: @@ -267,16 +416,116 @@ void apbt_setup_secondary_clock(void) {} #endif /* CONFIG_SMP */ +static void apbt_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long ctrl; + uint64_t delta; + int timer_num; + struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); + + BUG_ON(!apbt_virt_address); + + timer_num = adev->num; + pr_debug("%s CPU %d timer %d mode=%d\n", + __func__, first_cpu(*evt->cpumask), timer_num, mode); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * apbt_clockevent.mult; + delta >>= apbt_clockevent.shift; + ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); + ctrl |= APBTMR_CONTROL_MODE_PERIODIC; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + /* + * DW APB p. 46, have to disable timer before load counter, + * may cause sync problem. + */ + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + udelay(1); + pr_debug("Setting clock period %d for HZ %d\n", (int)delta, HZ); + apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); + ctrl |= APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + break; + /* APB timer does not have one-shot mode, use free running mode */ + case CLOCK_EVT_MODE_ONESHOT: + ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); + /* + * set free running mode, this mode will let timer reload max + * timeout which will give time (3min on 25MHz clock) to rearm + * the next event, therefore emulate the one-shot mode. + */ + ctrl &= ~APBTMR_CONTROL_ENABLE; + ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; + + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + /* write again to set free running mode */ + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + + /* + * DW APB p. 46, load counter with all 1s before starting free + * running mode. + */ + apbt_writel(timer_num, ~0, APBTMR_N_LOAD_COUNT); + ctrl &= ~APBTMR_CONTROL_INT; + ctrl |= APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + apbt_disable_int(timer_num); + ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + break; + + case CLOCK_EVT_MODE_RESUME: + apbt_enable_int(timer_num); + break; + } +} + +static int apbt_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + unsigned long ctrl; + int timer_num; + + struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); + + timer_num = adev->num; + /* Disable timer */ + ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + /* write new count */ + apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); + ctrl |= APBTMR_CONTROL_ENABLE; + apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); + return 0; +} + +static cycle_t apbt_read_clocksource(struct clocksource *cs) +{ + unsigned long current_count; + + current_count = apbt_readl(phy_cs_timer_id, APBTMR_N_CURRENT_VALUE); + return (cycle_t)~current_count; +} + static int apbt_clocksource_register(void) { u64 start, now; cycle_t t1; /* Start the counter, use timer 2 as source, timer 0/1 for event */ - dw_apb_clocksource_start(clocksource_apbt); + apbt_start_counter(phy_cs_timer_id); /* Verify whether apbt counter works */ - t1 = dw_apb_clocksource_read(clocksource_apbt); + t1 = apbt_read_clocksource(&clocksource_apbt); rdtscll(start); /* @@ -291,10 +540,10 @@ static int apbt_clocksource_register(void) } while ((now - start) < 200000UL); /* APBT is the only always on clocksource, it has to work! */ - if (t1 == dw_apb_clocksource_read(clocksource_apbt)) + if (t1 == apbt_read_clocksource(&clocksource_apbt)) panic("APBT counter not counting. APBT disabled\n"); - dw_apb_clocksource_register(clocksource_apbt); + clocksource_register_khz(&clocksource_apbt, (u32)apbt_freq*1000); return 0; } @@ -318,7 +567,10 @@ void __init apbt_time_init(void) if (apb_timer_block_enabled) return; apbt_set_mapping(); - if (!apbt_virt_address) + if (apbt_virt_address) { + pr_debug("Found APBT version 0x%lx\n",\ + apbt_readl_reg(APBTMRS_COMP_VERSION)); + } else goto out_noapbt; /* * Read the frequency and check for a sane value, for ESL model @@ -326,7 +578,7 @@ void __init apbt_time_init(void) */ if (apbt_freq < APBT_MIN_FREQ || apbt_freq > APBT_MAX_FREQ) { - pr_debug("APBT has invalid freq 0x%lx\n", apbt_freq); + pr_debug("APBT has invalid freq 0x%llx\n", apbt_freq); goto out_noapbt; } if (apbt_clocksource_register()) { @@ -352,20 +604,30 @@ void __init apbt_time_init(void) } else { percpu_timer = 0; apbt_num_timers_used = 1; + adev = &per_cpu(cpu_apbt_dev, 0); + adev->flags &= ~APBT_DEV_USED; } pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used); /* here we set up per CPU timer data structure */ + apbt_devs = kzalloc(sizeof(struct apbt_dev) * apbt_num_timers_used, + GFP_KERNEL); + if (!apbt_devs) { + printk(KERN_ERR "Failed to allocate APB timer devices\n"); + return; + } for (i = 0; i < apbt_num_timers_used; i++) { adev = &per_cpu(cpu_apbt_dev, i); adev->num = i; adev->cpu = i; p_mtmr = sfi_get_mtmr(i); - if (p_mtmr) + if (p_mtmr) { + adev->tick = p_mtmr->freq_hz; adev->irq = p_mtmr->irq; - else + } else printk(KERN_ERR "Failed to get timer for cpu %d\n", i); - snprintf(adev->name, sizeof(adev->name) - 1, "apbt%d", i); + adev->count = 0; + sprintf(adev->name, "apbt%d", i); } #endif @@ -377,8 +639,17 @@ void __init apbt_time_init(void) panic("failed to enable APB timer\n"); } +static inline void apbt_disable(int n) +{ + if (is_apbt_capable()) { + unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(n, ctrl, APBTMR_N_CONTROL); + } +} + /* called before apb_timer_enable, use early map */ -unsigned long apbt_quick_calibrate(void) +unsigned long apbt_quick_calibrate() { int i, scale; u64 old, new; @@ -387,31 +658,31 @@ unsigned long apbt_quick_calibrate(void) u32 loop, shift; apbt_set_mapping(); - dw_apb_clocksource_start(clocksource_apbt); + apbt_start_counter(phy_cs_timer_id); /* check if the timer can count down, otherwise return */ - old = dw_apb_clocksource_read(clocksource_apbt); + old = apbt_read_clocksource(&clocksource_apbt); i = 10000; while (--i) { - if (old != dw_apb_clocksource_read(clocksource_apbt)) + if (old != apbt_read_clocksource(&clocksource_apbt)) break; } if (!i) goto failed; /* count 16 ms */ - loop = (apbt_freq / 1000) << 4; + loop = (apbt_freq * 1000) << 4; /* restart the timer to ensure it won't get to 0 in the calibration */ - dw_apb_clocksource_start(clocksource_apbt); + apbt_start_counter(phy_cs_timer_id); - old = dw_apb_clocksource_read(clocksource_apbt); + old = apbt_read_clocksource(&clocksource_apbt); old += loop; t1 = __native_read_tsc(); do { - new = dw_apb_clocksource_read(clocksource_apbt); + new = apbt_read_clocksource(&clocksource_apbt); } while (new < old); t2 = __native_read_tsc(); @@ -423,7 +694,7 @@ unsigned long apbt_quick_calibrate(void) return 0; } scale = (int)div_u64((t2 - t1), loop >> shift); - khz = (scale * (apbt_freq / 1000)) >> shift; + khz = (scale * apbt_freq * 1000) >> shift; printk(KERN_INFO "TSC freq calculated by APB timer is %lu khz\n", khz); return khz; failed: diff --git a/trunk/arch/x86/kernel/apic/apic.c b/trunk/arch/x86/kernel/apic/apic.c index b24be38c8cf8..9498b8445186 100644 --- a/trunk/arch/x86/kernel/apic/apic.c +++ b/trunk/arch/x86/kernel/apic/apic.c @@ -1944,28 +1944,10 @@ void disconnect_bsp_APIC(int virt_wire_setup) void __cpuinit generic_processor_info(int apicid, int version) { - int cpu, max = nr_cpu_ids; - bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid, - phys_cpu_present_map); - - /* - * If boot cpu has not been detected yet, then only allow upto - * nr_cpu_ids - 1 processors and keep one slot free for boot cpu - */ - if (!boot_cpu_detected && num_processors >= nr_cpu_ids - 1 && - apicid != boot_cpu_physical_apicid) { - int thiscpu = max + disabled_cpus - 1; - - pr_warning( - "ACPI: NR_CPUS/possible_cpus limit of %i almost" - " reached. Keeping one slot for boot cpu." - " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); - - disabled_cpus++; - return; - } + int cpu; if (num_processors >= nr_cpu_ids) { + int max = nr_cpu_ids; int thiscpu = max + disabled_cpus; pr_warning( diff --git a/trunk/arch/x86/kernel/cpu/bugs.c b/trunk/arch/x86/kernel/cpu/bugs.c index 46674fbb62ba..525514cf33c3 100644 --- a/trunk/arch/x86/kernel/cpu/bugs.c +++ b/trunk/arch/x86/kernel/cpu/bugs.c @@ -62,8 +62,6 @@ static void __init check_fpu(void) return; } - kernel_fpu_begin(); - /* * trap_init() enabled FXSR and company _before_ testing for FP * problems here. @@ -82,8 +80,6 @@ static void __init check_fpu(void) : "=m" (*&fdiv_bug) : "m" (*&x), "m" (*&y)); - kernel_fpu_end(); - boot_cpu_data.fdiv_bug = fdiv_bug; if (boot_cpu_data.fdiv_bug) printk(KERN_WARNING "Hmm, FPU with FDIV bug.\n"); diff --git a/trunk/arch/x86/kernel/cpu/hypervisor.c b/trunk/arch/x86/kernel/cpu/hypervisor.c index 755f64fb0743..8095f8611f8a 100644 --- a/trunk/arch/x86/kernel/cpu/hypervisor.c +++ b/trunk/arch/x86/kernel/cpu/hypervisor.c @@ -32,11 +32,11 @@ */ static const __initconst struct hypervisor_x86 * const hypervisors[] = { + &x86_hyper_vmware, + &x86_hyper_ms_hyperv, #ifdef CONFIG_XEN_PVHVM &x86_hyper_xen_hvm, #endif - &x86_hyper_vmware, - &x86_hyper_ms_hyperv, }; const struct hypervisor_x86 *x86_hyper; diff --git a/trunk/arch/x86/kernel/quirks.c b/trunk/arch/x86/kernel/quirks.c index b78643d0f9a5..8bbe8c56916d 100644 --- a/trunk/arch/x86/kernel/quirks.c +++ b/trunk/arch/x86/kernel/quirks.c @@ -10,7 +10,7 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) { - u8 config; + u8 config, rev; u16 word; /* BIOS may enable hardware IRQ balancing for @@ -18,7 +18,8 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) * based platforms. * Disable SW irqbalance/affinity on those platforms. */ - if (dev->revision > 0x9) + pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); + if (rev > 0x9) return; /* enable access to config space*/ diff --git a/trunk/arch/x86/kernel/relocate_kernel_32.S b/trunk/arch/x86/kernel/relocate_kernel_32.S index 36818f8ec2be..41235531b11c 100644 --- a/trunk/arch/x86/kernel/relocate_kernel_32.S +++ b/trunk/arch/x86/kernel/relocate_kernel_32.S @@ -97,8 +97,6 @@ relocate_kernel: ret identity_mapped: - /* set return address to 0 if not preserving context */ - pushl $0 /* store the start address on the stack */ pushl %edx diff --git a/trunk/arch/x86/kernel/relocate_kernel_64.S b/trunk/arch/x86/kernel/relocate_kernel_64.S index 7a6f3b3be3cf..4de8f5b3d476 100644 --- a/trunk/arch/x86/kernel/relocate_kernel_64.S +++ b/trunk/arch/x86/kernel/relocate_kernel_64.S @@ -100,8 +100,6 @@ relocate_kernel: ret identity_mapped: - /* set return address to 0 if not preserving context */ - pushq $0 /* store the start address on the stack */ pushq %rdx diff --git a/trunk/arch/x86/kernel/tsc.c b/trunk/arch/x86/kernel/tsc.c index db483369f10b..56c633a5db72 100644 --- a/trunk/arch/x86/kernel/tsc.c +++ b/trunk/arch/x86/kernel/tsc.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -799,6 +800,27 @@ void mark_tsc_unstable(char *reason) EXPORT_SYMBOL_GPL(mark_tsc_unstable); +static int __init dmi_mark_tsc_unstable(const struct dmi_system_id *d) +{ + printk(KERN_NOTICE "%s detected: marking TSC unstable.\n", + d->ident); + tsc_unstable = 1; + return 0; +} + +/* List of systems that have known TSC problems */ +static struct dmi_system_id __initdata bad_tsc_dmi_table[] = { + { + .callback = dmi_mark_tsc_unstable, + .ident = "IBM Thinkpad 380XD", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), + DMI_MATCH(DMI_BOARD_NAME, "2635FA0"), + }, + }, + {} +}; + static void __init check_system_tsc_reliable(void) { #ifdef CONFIG_MGEODE_LX @@ -988,6 +1010,8 @@ void __init tsc_init(void) lpj_fine = lpj; use_tsc_delay(); + /* Check and install the TSC clocksource */ + dmi_check_system(bad_tsc_dmi_table); if (unsynchronized_tsc()) mark_tsc_unstable("TSCs unsynchronized"); diff --git a/trunk/arch/x86/kvm/Kconfig b/trunk/arch/x86/kvm/Kconfig index 65cf8233d25c..50f63648ce1b 100644 --- a/trunk/arch/x86/kvm/Kconfig +++ b/trunk/arch/x86/kvm/Kconfig @@ -76,5 +76,6 @@ config KVM_MMU_AUDIT # the virtualization menu. source drivers/vhost/Kconfig source drivers/lguest/Kconfig +source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/trunk/block/blk-core.c b/trunk/block/blk-core.c index 1d49e1c7c905..d2f8f4049abd 100644 --- a/trunk/block/blk-core.c +++ b/trunk/block/blk-core.c @@ -839,9 +839,6 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask) { struct request *rq; - if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) - return NULL; - BUG_ON(rw != READ && rw != WRITE); spin_lock_irq(q->queue_lock); diff --git a/trunk/block/blk-exec.c b/trunk/block/blk-exec.c index a1ebceb332f9..8a0e7ec056e7 100644 --- a/trunk/block/blk-exec.c +++ b/trunk/block/blk-exec.c @@ -50,13 +50,6 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, { int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; - if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) { - rq->errors = -ENXIO; - if (rq->end_io) - rq->end_io(rq, rq->errors); - return; - } - rq->rq_disk = bd_disk; rq->end_io = done; WARN_ON(irqs_disabled()); diff --git a/trunk/drivers/Kconfig b/trunk/drivers/Kconfig index 9e7a4f5b5c2e..52e306dd5010 100644 --- a/trunk/drivers/Kconfig +++ b/trunk/drivers/Kconfig @@ -112,8 +112,6 @@ source "drivers/uio/Kconfig" source "drivers/vlynq/Kconfig" -source "drivers/virtio/Kconfig" - source "drivers/xen/Kconfig" source "drivers/staging/Kconfig" diff --git a/trunk/drivers/base/Kconfig b/trunk/drivers/base/Kconfig index b605d01f5d45..d57e8d0fb823 100644 --- a/trunk/drivers/base/Kconfig +++ b/trunk/drivers/base/Kconfig @@ -168,6 +168,4 @@ config SYS_HYPERVISOR bool default n -source "drivers/base/regmap/Kconfig" - endmenu diff --git a/trunk/drivers/base/Makefile b/trunk/drivers/base/Makefile index 99a375ad2cc9..5ab0d07c4578 100644 --- a/trunk/drivers/base/Makefile +++ b/trunk/drivers/base/Makefile @@ -17,7 +17,6 @@ ifeq ($(CONFIG_SYSFS),y) obj-$(CONFIG_MODULES) += module.o endif obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o -obj-$(CONFIG_REGMAP) += regmap/ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/trunk/drivers/base/devtmpfs.c b/trunk/drivers/base/devtmpfs.c index 6d678c99512e..82bbb5967aa9 100644 --- a/trunk/drivers/base/devtmpfs.c +++ b/trunk/drivers/base/devtmpfs.c @@ -21,11 +21,12 @@ #include #include #include +#include #include +#include #include -#include -static struct task_struct *thread; +static struct vfsmount *dev_mnt; #if defined CONFIG_DEVTMPFS_MOUNT static int mount_dev = 1; @@ -33,16 +34,7 @@ static int mount_dev = 1; static int mount_dev; #endif -static DEFINE_SPINLOCK(req_lock); - -static struct req { - struct req *next; - struct completion done; - int err; - const char *name; - mode_t mode; /* 0 => delete */ - struct device *dev; -} *requests; +static DEFINE_MUTEX(dirlock); static int __init mount_param(char *str) { @@ -76,152 +68,131 @@ static inline int is_blockdev(struct device *dev) static inline int is_blockdev(struct device *dev) { return 0; } #endif -int devtmpfs_create_node(struct device *dev) -{ - const char *tmp = NULL; - struct req req; - - if (!thread) - return 0; - - req.mode = 0; - req.name = device_get_devnode(dev, &req.mode, &tmp); - if (!req.name) - return -ENOMEM; - - if (req.mode == 0) - req.mode = 0600; - if (is_blockdev(dev)) - req.mode |= S_IFBLK; - else - req.mode |= S_IFCHR; - - req.dev = dev; - - init_completion(&req.done); - - spin_lock(&req_lock); - req.next = requests; - requests = &req; - spin_unlock(&req_lock); - - wake_up_process(thread); - wait_for_completion(&req.done); - - kfree(tmp); - - return req.err; -} - -int devtmpfs_delete_node(struct device *dev) -{ - const char *tmp = NULL; - struct req req; - - if (!thread) - return 0; - - req.name = device_get_devnode(dev, NULL, &tmp); - if (!req.name) - return -ENOMEM; - - req.mode = 0; - req.dev = dev; - - init_completion(&req.done); - - spin_lock(&req_lock); - req.next = requests; - requests = &req; - spin_unlock(&req_lock); - - wake_up_process(thread); - wait_for_completion(&req.done); - - kfree(tmp); - return req.err; -} - static int dev_mkdir(const char *name, mode_t mode) { + struct nameidata nd; struct dentry *dentry; - struct path path; int err; - dentry = kern_path_create(AT_FDCWD, name, &path, 1); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - err = vfs_mkdir(path.dentry->d_inode, dentry, mode); - if (!err) - /* mark as kernel-created inode */ - dentry->d_inode->i_private = &thread; - dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, + name, LOOKUP_PARENT, &nd); + if (err) + return err; + + dentry = lookup_create(&nd, 1); + if (!IS_ERR(dentry)) { + err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); + if (!err) + /* mark as kernel-created inode */ + dentry->d_inode->i_private = &dev_mnt; + dput(dentry); + } else { + err = PTR_ERR(dentry); + } + + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); return err; } static int create_path(const char *nodepath) { - char *path; - char *s; int err; - /* parent directories do not exist, create them */ - path = kstrdup(nodepath, GFP_KERNEL); - if (!path) - return -ENOMEM; - - s = path; - for (;;) { - s = strchr(s, '/'); - if (!s) - break; - s[0] = '\0'; - err = dev_mkdir(path, 0755); - if (err && err != -EEXIST) - break; - s[0] = '/'; - s++; + mutex_lock(&dirlock); + err = dev_mkdir(nodepath, 0755); + if (err == -ENOENT) { + char *path; + char *s; + + /* parent directories do not exist, create them */ + path = kstrdup(nodepath, GFP_KERNEL); + if (!path) { + err = -ENOMEM; + goto out; + } + s = path; + for (;;) { + s = strchr(s, '/'); + if (!s) + break; + s[0] = '\0'; + err = dev_mkdir(path, 0755); + if (err && err != -EEXIST) + break; + s[0] = '/'; + s++; + } + kfree(path); } - kfree(path); +out: + mutex_unlock(&dirlock); return err; } -static int handle_create(const char *nodename, mode_t mode, struct device *dev) +int devtmpfs_create_node(struct device *dev) { + const char *tmp = NULL; + const char *nodename; + const struct cred *curr_cred; + mode_t mode = 0; + struct nameidata nd; struct dentry *dentry; - struct path path; int err; - dentry = kern_path_create(AT_FDCWD, nodename, &path, 0); - if (dentry == ERR_PTR(-ENOENT)) { + if (!dev_mnt) + return 0; + + nodename = device_get_devnode(dev, &mode, &tmp); + if (!nodename) + return -ENOMEM; + + if (mode == 0) + mode = 0600; + if (is_blockdev(dev)) + mode |= S_IFBLK; + else + mode |= S_IFCHR; + + curr_cred = override_creds(&init_cred); + + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, + nodename, LOOKUP_PARENT, &nd); + if (err == -ENOENT) { create_path(nodename); - dentry = kern_path_create(AT_FDCWD, nodename, &path, 0); + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, + nodename, LOOKUP_PARENT, &nd); } - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - err = vfs_mknod(path.dentry->d_inode, - dentry, mode, dev->devt); - if (!err) { - struct iattr newattrs; - - /* fixup possibly umasked mode */ - newattrs.ia_mode = mode; - newattrs.ia_valid = ATTR_MODE; - mutex_lock(&dentry->d_inode->i_mutex); - notify_change(dentry, &newattrs); - mutex_unlock(&dentry->d_inode->i_mutex); - - /* mark as kernel-created inode */ - dentry->d_inode->i_private = &thread; + if (err) + goto out; + + dentry = lookup_create(&nd, 0); + if (!IS_ERR(dentry)) { + err = vfs_mknod(nd.path.dentry->d_inode, + dentry, mode, dev->devt); + if (!err) { + struct iattr newattrs; + + /* fixup possibly umasked mode */ + newattrs.ia_mode = mode; + newattrs.ia_valid = ATTR_MODE; + mutex_lock(&dentry->d_inode->i_mutex); + notify_change(dentry, &newattrs); + mutex_unlock(&dentry->d_inode->i_mutex); + + /* mark as kernel-created inode */ + dentry->d_inode->i_private = &dev_mnt; + } + dput(dentry); + } else { + err = PTR_ERR(dentry); } - dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); +out: + kfree(tmp); + revert_creds(curr_cred); return err; } @@ -231,7 +202,8 @@ static int dev_rmdir(const char *name) struct dentry *dentry; int err; - err = kern_path_parent(name, &nd); + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, + name, LOOKUP_PARENT, &nd); if (err) return err; @@ -239,7 +211,7 @@ static int dev_rmdir(const char *name) dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); if (!IS_ERR(dentry)) { if (dentry->d_inode) { - if (dentry->d_inode->i_private == &thread) + if (dentry->d_inode->i_private == &dev_mnt) err = vfs_rmdir(nd.path.dentry->d_inode, dentry); else @@ -266,6 +238,7 @@ static int delete_path(const char *nodepath) if (!path) return -ENOMEM; + mutex_lock(&dirlock); for (;;) { char *base; @@ -277,6 +250,7 @@ static int delete_path(const char *nodepath) if (err) break; } + mutex_unlock(&dirlock); kfree(path); return err; @@ -285,7 +259,7 @@ static int delete_path(const char *nodepath) static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat) { /* did we create it */ - if (inode->i_private != &thread) + if (inode->i_private != &dev_mnt) return 0; /* does the dev_t match */ @@ -303,17 +277,29 @@ static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *sta return 1; } -static int handle_remove(const char *nodename, struct device *dev) +int devtmpfs_delete_node(struct device *dev) { + const char *tmp = NULL; + const char *nodename; + const struct cred *curr_cred; struct nameidata nd; struct dentry *dentry; struct kstat stat; int deleted = 1; int err; - err = kern_path_parent(nodename, &nd); + if (!dev_mnt) + return 0; + + nodename = device_get_devnode(dev, NULL, &tmp); + if (!nodename) + return -ENOMEM; + + curr_cred = override_creds(&init_cred); + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, + nodename, LOOKUP_PARENT, &nd); if (err) - return err; + goto out; mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); @@ -351,6 +337,9 @@ static int handle_remove(const char *nodename, struct device *dev) path_put(&nd.path); if (deleted && strchr(nodename, '/')) delete_path(nodename); +out: + kfree(tmp); + revert_creds(curr_cred); return err; } @@ -365,7 +354,7 @@ int devtmpfs_mount(const char *mntdir) if (!mount_dev) return 0; - if (!thread) + if (!dev_mnt) return 0; err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL); @@ -376,79 +365,31 @@ int devtmpfs_mount(const char *mntdir) return err; } -static __initdata DECLARE_COMPLETION(setup_done); - -static int handle(const char *name, mode_t mode, struct device *dev) -{ - if (mode) - return handle_create(name, mode, dev); - else - return handle_remove(name, dev); -} - -static int devtmpfsd(void *p) -{ - char options[] = "mode=0755"; - int *err = p; - *err = sys_unshare(CLONE_NEWNS); - if (*err) - goto out; - *err = sys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options); - if (*err) - goto out; - sys_chdir("/.."); /* will traverse into overmounted root */ - sys_chroot("."); - complete(&setup_done); - while (1) { - spin_lock(&req_lock); - while (requests) { - struct req *req = requests; - requests = NULL; - spin_unlock(&req_lock); - while (req) { - req->err = handle(req->name, req->mode, req->dev); - complete(&req->done); - req = req->next; - } - spin_lock(&req_lock); - } - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock(&req_lock); - schedule(); - __set_current_state(TASK_RUNNING); - } - return 0; -out: - complete(&setup_done); - return *err; -} - /* * Create devtmpfs instance, driver-core devices will add their device * nodes here. */ int __init devtmpfs_init(void) { - int err = register_filesystem(&dev_fs_type); + int err; + struct vfsmount *mnt; + char options[] = "mode=0755"; + + err = register_filesystem(&dev_fs_type); if (err) { printk(KERN_ERR "devtmpfs: unable to register devtmpfs " "type %i\n", err); return err; } - thread = kthread_run(devtmpfsd, &err, "kdevtmpfs"); - if (!IS_ERR(thread)) { - wait_for_completion(&setup_done); - } else { - err = PTR_ERR(thread); - thread = NULL; - } - - if (err) { + mnt = kern_mount_data(&dev_fs_type, options); + if (IS_ERR(mnt)) { + err = PTR_ERR(mnt); printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); unregister_filesystem(&dev_fs_type); return err; } + dev_mnt = mnt; printk(KERN_INFO "devtmpfs: initialized\n"); return 0; diff --git a/trunk/drivers/base/regmap/Kconfig b/trunk/drivers/base/regmap/Kconfig deleted file mode 100644 index fabbf6cc5367..000000000000 --- a/trunk/drivers/base/regmap/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# Generic register map support. There are no user servicable options here, -# this is an API intended to be used by other kernel subsystems. These -# subsystems should select the appropriate symbols. - -config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI) - bool - -config REGMAP_I2C - tristate - -config REGMAP_SPI - tristate diff --git a/trunk/drivers/base/regmap/Makefile b/trunk/drivers/base/regmap/Makefile deleted file mode 100644 index f476f4571295..000000000000 --- a/trunk/drivers/base/regmap/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_REGMAP) += regmap.o -obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o -obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o diff --git a/trunk/drivers/base/regmap/regmap-i2c.c b/trunk/drivers/base/regmap/regmap-i2c.c deleted file mode 100644 index c2231ff06cbc..000000000000 --- a/trunk/drivers/base/regmap/regmap-i2c.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Register map access API - I2C support - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * 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 -#include -#include -#include - -static int regmap_i2c_write(struct device *dev, const void *data, size_t count) -{ - struct i2c_client *i2c = to_i2c_client(dev); - int ret; - - ret = i2c_master_send(i2c, data, count); - if (ret == count) - return 0; - else if (ret < 0) - return ret; - else - return -EIO; -} - -static int regmap_i2c_gather_write(struct device *dev, - const void *reg, size_t reg_size, - const void *val, size_t val_size) -{ - struct i2c_client *i2c = to_i2c_client(dev); - struct i2c_msg xfer[2]; - int ret; - - /* If the I2C controller can't do a gather tell the core, it - * will substitute in a linear write for us. - */ - if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_PROTOCOL_MANGLING)) - return -ENOTSUPP; - - xfer[0].addr = i2c->addr; - xfer[0].flags = 0; - xfer[0].len = reg_size; - xfer[0].buf = (void *)reg; - - xfer[1].addr = i2c->addr; - xfer[1].flags = I2C_M_NOSTART; - xfer[1].len = val_size; - xfer[1].buf = (void *)val; - - ret = i2c_transfer(i2c->adapter, xfer, 2); - if (ret == 2) - return 0; - if (ret < 0) - return ret; - else - return -EIO; -} - -static int regmap_i2c_read(struct device *dev, - const void *reg, size_t reg_size, - void *val, size_t val_size) -{ - struct i2c_client *i2c = to_i2c_client(dev); - struct i2c_msg xfer[2]; - int ret; - - xfer[0].addr = i2c->addr; - xfer[0].flags = 0; - xfer[0].len = reg_size; - xfer[0].buf = (void *)reg; - - xfer[1].addr = i2c->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = val_size; - xfer[1].buf = val; - - ret = i2c_transfer(i2c->adapter, xfer, 2); - if (ret == 2) - return 0; - else if (ret < 0) - return ret; - else - return -EIO; -} - -static struct regmap_bus regmap_i2c = { - .type = &i2c_bus_type, - .write = regmap_i2c_write, - .gather_write = regmap_i2c_gather_write, - .read = regmap_i2c_read, - .owner = THIS_MODULE, -}; - -/** - * regmap_init_i2c(): Initialise register map - * - * @i2c: Device that will be interacted with - * @config: Configuration for register map - * - * The return value will be an ERR_PTR() on error or a valid pointer to - * a struct regmap. - */ -struct regmap *regmap_init_i2c(struct i2c_client *i2c, - const struct regmap_config *config) -{ - return regmap_init(&i2c->dev, ®map_i2c, config); -} -EXPORT_SYMBOL_GPL(regmap_init_i2c); - diff --git a/trunk/drivers/base/regmap/regmap-spi.c b/trunk/drivers/base/regmap/regmap-spi.c deleted file mode 100644 index 4deba0621bc7..000000000000 --- a/trunk/drivers/base/regmap/regmap-spi.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Register map access API - SPI support - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * 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 -#include -#include - -static int regmap_spi_write(struct device *dev, const void *data, size_t count) -{ - struct spi_device *spi = to_spi_device(dev); - - return spi_write(spi, data, count); -} - -static int regmap_spi_gather_write(struct device *dev, - const void *reg, size_t reg_len, - const void *val, size_t val_len) -{ - struct spi_device *spi = to_spi_device(dev); - struct spi_message m; - struct spi_transfer t[2] = { { .tx_buf = reg, .len = reg_len, }, - { .tx_buf = val, .len = val_len, }, }; - - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - - return spi_sync(spi, &m); -} - -static int regmap_spi_read(struct device *dev, - const void *reg, size_t reg_size, - void *val, size_t val_size) -{ - struct spi_device *spi = to_spi_device(dev); - - return spi_write_then_read(spi, reg, reg_size, val, val_size); -} - -static struct regmap_bus regmap_spi = { - .type = &spi_bus_type, - .write = regmap_spi_write, - .gather_write = regmap_spi_gather_write, - .read = regmap_spi_read, - .owner = THIS_MODULE, - .read_flag_mask = 0x80, -}; - -/** - * regmap_init_spi(): Initialise register map - * - * @spi: Device that will be interacted with - * @config: Configuration for register map - * - * The return value will be an ERR_PTR() on error or a valid pointer to - * a struct regmap. - */ -struct regmap *regmap_init_spi(struct spi_device *spi, - const struct regmap_config *config) -{ - return regmap_init(&spi->dev, ®map_spi, config); -} -EXPORT_SYMBOL_GPL(regmap_init_spi); diff --git a/trunk/drivers/base/regmap/regmap.c b/trunk/drivers/base/regmap/regmap.c deleted file mode 100644 index cf3565cae93d..000000000000 --- a/trunk/drivers/base/regmap/regmap.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Register map access API - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * 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 -#include -#include -#include - -#include - -struct regmap; - -struct regmap_format { - size_t buf_size; - size_t reg_bytes; - size_t val_bytes; - void (*format_write)(struct regmap *map, - unsigned int reg, unsigned int val); - void (*format_reg)(void *buf, unsigned int reg); - void (*format_val)(void *buf, unsigned int val); - unsigned int (*parse_val)(void *buf); -}; - -struct regmap { - struct mutex lock; - - struct device *dev; /* Device we do I/O on */ - void *work_buf; /* Scratch buffer used to format I/O */ - struct regmap_format format; /* Buffer format */ - const struct regmap_bus *bus; -}; - -static void regmap_format_4_12_write(struct regmap *map, - unsigned int reg, unsigned int val) -{ - __be16 *out = map->work_buf; - *out = cpu_to_be16((reg << 12) | val); -} - -static void regmap_format_7_9_write(struct regmap *map, - unsigned int reg, unsigned int val) -{ - __be16 *out = map->work_buf; - *out = cpu_to_be16((reg << 9) | val); -} - -static void regmap_format_8(void *buf, unsigned int val) -{ - u8 *b = buf; - - b[0] = val; -} - -static void regmap_format_16(void *buf, unsigned int val) -{ - __be16 *b = buf; - - b[0] = cpu_to_be16(val); -} - -static unsigned int regmap_parse_8(void *buf) -{ - u8 *b = buf; - - return b[0]; -} - -static unsigned int regmap_parse_16(void *buf) -{ - __be16 *b = buf; - - b[0] = be16_to_cpu(b[0]); - - return b[0]; -} - -/** - * regmap_init(): Initialise register map - * - * @dev: Device that will be interacted with - * @bus: Bus-specific callbacks to use with device - * @config: Configuration for register map - * - * The return value will be an ERR_PTR() on error or a valid pointer to - * a struct regmap. This function should generally not be called - * directly, it should be called by bus-specific init functions. - */ -struct regmap *regmap_init(struct device *dev, - const struct regmap_bus *bus, - const struct regmap_config *config) -{ - struct regmap *map; - int ret = -EINVAL; - - if (!bus || !config) - return NULL; - - map = kzalloc(sizeof(*map), GFP_KERNEL); - if (map == NULL) { - ret = -ENOMEM; - goto err; - } - - mutex_init(&map->lock); - map->format.buf_size = (config->reg_bits + config->val_bits) / 8; - map->format.reg_bytes = config->reg_bits / 8; - map->format.val_bytes = config->val_bits / 8; - map->dev = dev; - map->bus = bus; - - switch (config->reg_bits) { - case 4: - switch (config->val_bits) { - case 12: - map->format.format_write = regmap_format_4_12_write; - break; - default: - goto err_map; - } - break; - - case 7: - switch (config->val_bits) { - case 9: - map->format.format_write = regmap_format_7_9_write; - break; - default: - goto err_map; - } - break; - - case 8: - map->format.format_reg = regmap_format_8; - break; - - case 16: - map->format.format_reg = regmap_format_16; - break; - - default: - goto err_map; - } - - switch (config->val_bits) { - case 8: - map->format.format_val = regmap_format_8; - map->format.parse_val = regmap_parse_8; - break; - case 16: - map->format.format_val = regmap_format_16; - map->format.parse_val = regmap_parse_16; - break; - } - - if (!map->format.format_write && - !(map->format.format_reg && map->format.format_val)) - goto err_map; - - map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL); - if (map->work_buf == NULL) { - ret = -ENOMEM; - goto err_bus; - } - - return map; - -err_bus: - module_put(map->bus->owner); -err_map: - kfree(map); -err: - return ERR_PTR(ret); -} -EXPORT_SYMBOL_GPL(regmap_init); - -/** - * regmap_exit(): Free a previously allocated register map - */ -void regmap_exit(struct regmap *map) -{ - kfree(map->work_buf); - module_put(map->bus->owner); - kfree(map); -} -EXPORT_SYMBOL_GPL(regmap_exit); - -static int _regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len) -{ - void *buf; - int ret = -ENOTSUPP; - size_t len; - - map->format.format_reg(map->work_buf, reg); - - /* Try to do a gather write if we can */ - if (map->bus->gather_write) - ret = map->bus->gather_write(map->dev, map->work_buf, - map->format.reg_bytes, - val, val_len); - - /* Otherwise fall back on linearising by hand. */ - if (ret == -ENOTSUPP) { - len = map->format.reg_bytes + val_len; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - memcpy(buf, map->work_buf, map->format.reg_bytes); - memcpy(buf + map->format.reg_bytes, val, val_len); - ret = map->bus->write(map->dev, buf, len); - - kfree(buf); - } - - return ret; -} - -static int _regmap_write(struct regmap *map, unsigned int reg, - unsigned int val) -{ - BUG_ON(!map->format.format_write && !map->format.format_val); - - if (map->format.format_write) { - map->format.format_write(map, reg, val); - - return map->bus->write(map->dev, map->work_buf, - map->format.buf_size); - } else { - map->format.format_val(map->work_buf + map->format.reg_bytes, - val); - return _regmap_raw_write(map, reg, - map->work_buf + map->format.reg_bytes, - map->format.val_bytes); - } -} - -/** - * regmap_write(): Write a value to a single register - * - * @map: Register map to write to - * @reg: Register to write to - * @val: Value to be written - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) -{ - int ret; - - mutex_lock(&map->lock); - - ret = _regmap_write(map, reg, val); - - mutex_unlock(&map->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_write); - -/** - * regmap_raw_write(): Write raw values to one or more registers - * - * @map: Register map to write to - * @reg: Initial register to write to - * @val: Block of data to be written, laid out for direct transmission to the - * device - * @val_len: Length of data pointed to by val. - * - * This function is intended to be used for things like firmware - * download where a large block of data needs to be transferred to the - * device. No formatting will be done on the data provided. - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len) -{ - int ret; - - mutex_lock(&map->lock); - - ret = _regmap_raw_write(map, reg, val, val_len); - - mutex_unlock(&map->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_raw_write); - -static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, - unsigned int val_len) -{ - u8 *u8 = map->work_buf; - int ret; - - map->format.format_reg(map->work_buf, reg); - - /* - * Some buses flag reads by setting the high bits in the - * register addresss; since it's always the high bits for all - * current formats we can do this here rather than in - * formatting. This may break if we get interesting formats. - */ - if (map->bus->read_flag_mask) - u8[0] |= map->bus->read_flag_mask; - - ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes, - val, map->format.val_bytes); - if (ret != 0) - return ret; - - return 0; -} - -static int _regmap_read(struct regmap *map, unsigned int reg, - unsigned int *val) -{ - int ret; - - if (!map->format.parse_val) - return -EINVAL; - - ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes); - if (ret == 0) - *val = map->format.parse_val(map->work_buf); - - return ret; -} - -/** - * regmap_read(): Read a value from a single register - * - * @map: Register map to write to - * @reg: Register to be read from - * @val: Pointer to store read value - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) -{ - int ret; - - mutex_lock(&map->lock); - - ret = _regmap_read(map, reg, val); - - mutex_unlock(&map->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_read); - -/** - * regmap_raw_read(): Read raw data from the device - * - * @map: Register map to write to - * @reg: First register to be read from - * @val: Pointer to store read value - * @val_len: Size of data to read - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, - size_t val_len) -{ - int ret; - - mutex_lock(&map->lock); - - ret = _regmap_raw_read(map, reg, val, val_len); - - mutex_unlock(&map->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_raw_read); - -/** - * regmap_bulk_read(): Read multiple registers from the device - * - * @map: Register map to write to - * @reg: First register to be read from - * @val: Pointer to store read value, in native register size for device - * @val_count: Number of registers to read - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, - size_t val_count) -{ - int ret, i; - size_t val_bytes = map->format.val_bytes; - - if (!map->format.parse_val) - return -EINVAL; - - ret = regmap_raw_read(map, reg, val, val_bytes * val_count); - if (ret != 0) - return ret; - - for (i = 0; i < val_count * val_bytes; i += val_bytes) - map->format.parse_val(val + i); - - return 0; -} -EXPORT_SYMBOL_GPL(regmap_bulk_read); - -/** - * remap_update_bits: Perform a read/modify/write cycle on the register map - * - * @map: Register map to update - * @reg: Register to update - * @mask: Bitmask to change - * @val: New value for bitmask - * - * Returns zero for success, a negative number on error. - */ -int regmap_update_bits(struct regmap *map, unsigned int reg, - unsigned int mask, unsigned int val) -{ - int ret; - unsigned int tmp; - - mutex_lock(&map->lock); - - ret = _regmap_read(map, reg, &tmp); - if (ret != 0) - goto out; - - tmp &= ~mask; - tmp |= val & mask; - - ret = _regmap_write(map, reg, tmp); - -out: - mutex_unlock(&map->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_update_bits); diff --git a/trunk/drivers/block/pktcdvd.c b/trunk/drivers/block/pktcdvd.c index e133f094ab08..07a382eaf0a8 100644 --- a/trunk/drivers/block/pktcdvd.c +++ b/trunk/drivers/block/pktcdvd.c @@ -1206,7 +1206,7 @@ static int pkt_start_recovery(struct packet_data *pkt) if (!sb) return 0; - if (!sb->s_op->relocate_blocks) + if (!sb->s_op || !sb->s_op->relocate_blocks) goto out; old_block = pkt->sector / (CD_FRAMESIZE >> 9); diff --git a/trunk/drivers/char/generic_nvram.c b/trunk/drivers/char/generic_nvram.c index 6c4f4b5a9dd3..0e941b57482e 100644 --- a/trunk/drivers/char/generic_nvram.c +++ b/trunk/drivers/char/generic_nvram.c @@ -34,16 +34,12 @@ static ssize_t nvram_len; static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) { switch (origin) { - case 0: - break; case 1: offset += file->f_pos; break; case 2: offset += nvram_len; break; - default: - offset = -1; } if (offset < 0) return -EINVAL; diff --git a/trunk/drivers/char/nvram.c b/trunk/drivers/char/nvram.c index da3cfee782dc..166f1e7aaa7e 100644 --- a/trunk/drivers/char/nvram.c +++ b/trunk/drivers/char/nvram.c @@ -224,8 +224,6 @@ static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) case 2: offset += NVRAM_BYTES; break; - default: - return -EINVAL; } return (offset >= 0) ? (file->f_pos = offset) : -EINVAL; diff --git a/trunk/drivers/char/ps3flash.c b/trunk/drivers/char/ps3flash.c index d0c57c2e2909..85c004a518ee 100644 --- a/trunk/drivers/char/ps3flash.c +++ b/trunk/drivers/char/ps3flash.c @@ -101,16 +101,12 @@ static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) mutex_lock(&file->f_mapping->host->i_mutex); switch (origin) { - case 0: - break; case 1: offset += file->f_pos; break; case 2: offset += dev->regions[dev->region_idx].size*dev->blk_size; break; - default: - offset = -1; } if (offset < 0) { res = -EINVAL; @@ -309,14 +305,9 @@ static int ps3flash_flush(struct file *file, fl_owner_t id) return ps3flash_writeback(ps3flash_dev); } -static int ps3flash_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int ps3flash_fsync(struct file *file, int datasync) { - struct inode *inode = file->f_path.dentry->d_inode; - int err; - mutex_lock(&inode->i_mutex); - err = ps3flash_writeback(ps3flash_dev); - mutex_unlock(&inode->i_mutex); - return err; + return ps3flash_writeback(ps3flash_dev); } static irqreturn_t ps3flash_interrupt(int irq, void *data) diff --git a/trunk/drivers/clocksource/Kconfig b/trunk/drivers/clocksource/Kconfig index 34e9c4f88926..d8d3e02b912c 100644 --- a/trunk/drivers/clocksource/Kconfig +++ b/trunk/drivers/clocksource/Kconfig @@ -12,6 +12,3 @@ config CLKBLD_I8253 config CLKSRC_MMIO bool - -config DW_APB_TIMER - bool diff --git a/trunk/drivers/clocksource/Makefile b/trunk/drivers/clocksource/Makefile index 85ad1646a7b7..7922a0cfc99f 100644 --- a/trunk/drivers/clocksource/Makefile +++ b/trunk/drivers/clocksource/Makefile @@ -8,4 +8,3 @@ obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o -obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o diff --git a/trunk/drivers/clocksource/dw_apb_timer.c b/trunk/drivers/clocksource/dw_apb_timer.c deleted file mode 100644 index 580f870541a3..000000000000 --- a/trunk/drivers/clocksource/dw_apb_timer.c +++ /dev/null @@ -1,401 +0,0 @@ -/* - * (C) Copyright 2009 Intel Corporation - * Author: Jacob Pan (jacob.jun.pan@intel.com) - * - * Shared with ARM platforms, Jamie Iles, Picochip 2011 - * - * 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. - * - * Support for the Synopsys DesignWare APB Timers. - */ -#include -#include -#include -#include -#include -#include -#include - -#define APBT_MIN_PERIOD 4 -#define APBT_MIN_DELTA_USEC 200 - -#define APBTMR_N_LOAD_COUNT 0x00 -#define APBTMR_N_CURRENT_VALUE 0x04 -#define APBTMR_N_CONTROL 0x08 -#define APBTMR_N_EOI 0x0c -#define APBTMR_N_INT_STATUS 0x10 - -#define APBTMRS_INT_STATUS 0xa0 -#define APBTMRS_EOI 0xa4 -#define APBTMRS_RAW_INT_STATUS 0xa8 -#define APBTMRS_COMP_VERSION 0xac - -#define APBTMR_CONTROL_ENABLE (1 << 0) -/* 1: periodic, 0:free running. */ -#define APBTMR_CONTROL_MODE_PERIODIC (1 << 1) -#define APBTMR_CONTROL_INT (1 << 2) - -static inline struct dw_apb_clock_event_device * -ced_to_dw_apb_ced(struct clock_event_device *evt) -{ - return container_of(evt, struct dw_apb_clock_event_device, ced); -} - -static inline struct dw_apb_clocksource * -clocksource_to_dw_apb_clocksource(struct clocksource *cs) -{ - return container_of(cs, struct dw_apb_clocksource, cs); -} - -static unsigned long apbt_readl(struct dw_apb_timer *timer, unsigned long offs) -{ - return readl(timer->base + offs); -} - -static void apbt_writel(struct dw_apb_timer *timer, unsigned long val, - unsigned long offs) -{ - writel(val, timer->base + offs); -} - -static void apbt_disable_int(struct dw_apb_timer *timer) -{ - unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); - - ctrl |= APBTMR_CONTROL_INT; - apbt_writel(timer, ctrl, APBTMR_N_CONTROL); -} - -/** - * dw_apb_clockevent_pause() - stop the clock_event_device from running - * - * @dw_ced: The APB clock to stop generating events. - */ -void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced) -{ - disable_irq(dw_ced->timer.irq); - apbt_disable_int(&dw_ced->timer); -} - -static void apbt_eoi(struct dw_apb_timer *timer) -{ - apbt_readl(timer, APBTMR_N_EOI); -} - -static irqreturn_t dw_apb_clockevent_irq(int irq, void *data) -{ - struct clock_event_device *evt = data; - struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); - - if (!evt->event_handler) { - pr_info("Spurious APBT timer interrupt %d", irq); - return IRQ_NONE; - } - - if (dw_ced->eoi) - dw_ced->eoi(&dw_ced->timer); - - evt->event_handler(evt); - return IRQ_HANDLED; -} - -static void apbt_enable_int(struct dw_apb_timer *timer) -{ - unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); - /* clear pending intr */ - apbt_readl(timer, APBTMR_N_EOI); - ctrl &= ~APBTMR_CONTROL_INT; - apbt_writel(timer, ctrl, APBTMR_N_CONTROL); -} - -static void apbt_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - unsigned long ctrl; - unsigned long period; - struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); - - pr_debug("%s CPU %d mode=%d\n", __func__, first_cpu(*evt->cpumask), - mode); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - ctrl |= APBTMR_CONTROL_MODE_PERIODIC; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - /* - * DW APB p. 46, have to disable timer before load counter, - * may cause sync problem. - */ - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - udelay(1); - pr_debug("Setting clock period %lu for HZ %d\n", period, HZ); - apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT); - ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_ONESHOT: - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - /* - * set free running mode, this mode will let timer reload max - * timeout which will give time (3min on 25MHz clock) to rearm - * the next event, therefore emulate the one-shot mode. - */ - ctrl &= ~APBTMR_CONTROL_ENABLE; - ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; - - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - /* write again to set free running mode */ - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - - /* - * DW APB p. 46, load counter with all 1s before starting free - * running mode. - */ - apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT); - ctrl &= ~APBTMR_CONTROL_INT; - ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_RESUME: - apbt_enable_int(&dw_ced->timer); - break; - } -} - -static int apbt_next_event(unsigned long delta, - struct clock_event_device *evt) -{ - unsigned long ctrl; - struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); - - /* Disable timer */ - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - /* write new count */ - apbt_writel(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT); - ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - - return 0; -} - -/** - * dw_apb_clockevent_init() - use an APB timer as a clock_event_device - * - * @cpu: The CPU the events will be targeted at. - * @name: The name used for the timer and the IRQ for it. - * @rating: The rating to give the timer. - * @base: I/O base for the timer registers. - * @irq: The interrupt number to use for the timer. - * @freq: The frequency that the timer counts at. - * - * This creates a clock_event_device for using with the generic clock layer - * but does not start and register it. This should be done with - * dw_apb_clockevent_register() as the next step. If this is the first time - * it has been called for a timer then the IRQ will be requested, if not it - * just be enabled to allow CPU hotplug to avoid repeatedly requesting and - * releasing the IRQ. - */ -struct dw_apb_clock_event_device * -dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, - void __iomem *base, int irq, unsigned long freq) -{ - struct dw_apb_clock_event_device *dw_ced = - kzalloc(sizeof(*dw_ced), GFP_KERNEL); - int err; - - if (!dw_ced) - return NULL; - - dw_ced->timer.base = base; - dw_ced->timer.irq = irq; - dw_ced->timer.freq = freq; - - clockevents_calc_mult_shift(&dw_ced->ced, freq, APBT_MIN_PERIOD); - dw_ced->ced.max_delta_ns = clockevent_delta2ns(0x7fffffff, - &dw_ced->ced); - dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced); - dw_ced->ced.cpumask = cpumask_of(cpu); - dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - dw_ced->ced.set_mode = apbt_set_mode; - dw_ced->ced.set_next_event = apbt_next_event; - dw_ced->ced.irq = dw_ced->timer.irq; - dw_ced->ced.rating = rating; - dw_ced->ced.name = name; - - dw_ced->irqaction.name = dw_ced->ced.name; - dw_ced->irqaction.handler = dw_apb_clockevent_irq; - dw_ced->irqaction.dev_id = &dw_ced->ced; - dw_ced->irqaction.irq = irq; - dw_ced->irqaction.flags = IRQF_TIMER | IRQF_IRQPOLL | - IRQF_NOBALANCING | - IRQF_DISABLED; - - dw_ced->eoi = apbt_eoi; - err = setup_irq(irq, &dw_ced->irqaction); - if (err) { - pr_err("failed to request timer irq\n"); - kfree(dw_ced); - dw_ced = NULL; - } - - return dw_ced; -} - -/** - * dw_apb_clockevent_resume() - resume a clock that has been paused. - * - * @dw_ced: The APB clock to resume. - */ -void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced) -{ - enable_irq(dw_ced->timer.irq); -} - -/** - * dw_apb_clockevent_stop() - stop the clock_event_device and release the IRQ. - * - * @dw_ced: The APB clock to stop generating the events. - */ -void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced) -{ - free_irq(dw_ced->timer.irq, &dw_ced->ced); -} - -/** - * dw_apb_clockevent_register() - register the clock with the generic layer - * - * @dw_ced: The APB clock to register as a clock_event_device. - */ -void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced) -{ - apbt_writel(&dw_ced->timer, 0, APBTMR_N_CONTROL); - clockevents_register_device(&dw_ced->ced); - apbt_enable_int(&dw_ced->timer); -} - -/** - * dw_apb_clocksource_start() - start the clocksource counting. - * - * @dw_cs: The clocksource to start. - * - * This is used to start the clocksource before registration and can be used - * to enable calibration of timers. - */ -void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs) -{ - /* - * start count down from 0xffff_ffff. this is done by toggling the - * enable bit then load initial load count to ~0. - */ - unsigned long ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL); - - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); - apbt_writel(&dw_cs->timer, ~0, APBTMR_N_LOAD_COUNT); - /* enable, mask interrupt */ - ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; - ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); - apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); - /* read it once to get cached counter value initialized */ - dw_apb_clocksource_read(dw_cs); -} - -static cycle_t __apbt_read_clocksource(struct clocksource *cs) -{ - unsigned long current_count; - struct dw_apb_clocksource *dw_cs = - clocksource_to_dw_apb_clocksource(cs); - - current_count = apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); - - return (cycle_t)~current_count; -} - -static void apbt_restart_clocksource(struct clocksource *cs) -{ - struct dw_apb_clocksource *dw_cs = - clocksource_to_dw_apb_clocksource(cs); - - dw_apb_clocksource_start(dw_cs); -} - -/** - * dw_apb_clocksource_init() - use an APB timer as a clocksource. - * - * @rating: The rating to give the clocksource. - * @name: The name for the clocksource. - * @base: The I/O base for the timer registers. - * @freq: The frequency that the timer counts at. - * - * This creates a clocksource using an APB timer but does not yet register it - * with the clocksource system. This should be done with - * dw_apb_clocksource_register() as the next step. - */ -struct dw_apb_clocksource * -dw_apb_clocksource_init(unsigned rating, char *name, void __iomem *base, - unsigned long freq) -{ - struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL); - - if (!dw_cs) - return NULL; - - dw_cs->timer.base = base; - dw_cs->timer.freq = freq; - dw_cs->cs.name = name; - dw_cs->cs.rating = rating; - dw_cs->cs.read = __apbt_read_clocksource; - dw_cs->cs.mask = CLOCKSOURCE_MASK(32); - dw_cs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; - dw_cs->cs.resume = apbt_restart_clocksource; - - return dw_cs; -} - -/** - * dw_apb_clocksource_register() - register the APB clocksource. - * - * @dw_cs: The clocksource to register. - */ -void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs) -{ - clocksource_register_hz(&dw_cs->cs, dw_cs->timer.freq); -} - -/** - * dw_apb_clocksource_read() - read the current value of a clocksource. - * - * @dw_cs: The clocksource to read. - */ -cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs) -{ - return (cycle_t)~apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); -} - -/** - * dw_apb_clocksource_unregister() - unregister and free a clocksource. - * - * @dw_cs: The clocksource to unregister/free. - */ -void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs) -{ - clocksource_unregister(&dw_cs->cs); - - kfree(dw_cs); -} diff --git a/trunk/drivers/firmware/iscsi_ibft.c b/trunk/drivers/firmware/iscsi_ibft.c index c811cb107904..ce33f4626957 100644 --- a/trunk/drivers/firmware/iscsi_ibft.c +++ b/trunk/drivers/firmware/iscsi_ibft.c @@ -566,11 +566,6 @@ static mode_t __init ibft_check_initiator_for(void *data, int type) return rc; } -static void ibft_kobj_release(void *data) -{ - kfree(data); -} - /* * Helper function for ibft_register_kobjects. */ @@ -600,8 +595,7 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index, ibft_kobj, ibft_attr_show_initiator, - ibft_check_initiator_for, - ibft_kobj_release); + ibft_check_initiator_for); if (!boot_kobj) { rc = -ENOMEM; goto free_ibft_obj; @@ -616,8 +610,7 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index, ibft_kobj, ibft_attr_show_nic, - ibft_check_nic_for, - ibft_kobj_release); + ibft_check_nic_for); if (!boot_kobj) { rc = -ENOMEM; goto free_ibft_obj; @@ -632,8 +625,7 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index, ibft_kobj, ibft_attr_show_target, - ibft_check_tgt_for, - ibft_kobj_release); + ibft_check_tgt_for); if (!boot_kobj) { rc = -ENOMEM; goto free_ibft_obj; diff --git a/trunk/drivers/macintosh/nvram.c b/trunk/drivers/macintosh/nvram.c index f0e03e7937e3..a271c8218d82 100644 --- a/trunk/drivers/macintosh/nvram.c +++ b/trunk/drivers/macintosh/nvram.c @@ -21,16 +21,12 @@ static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) { switch (origin) { - case 0: - break; case 1: offset += file->f_pos; break; case 2: offset += NVRAM_SIZE; break; - default: - offset = -1; } if (offset < 0) return -EINVAL; diff --git a/trunk/drivers/md/md.c b/trunk/drivers/md/md.c index dfc9425db70b..91e31e260b4a 100644 --- a/trunk/drivers/md/md.c +++ b/trunk/drivers/md/md.c @@ -6394,11 +6394,16 @@ static void md_seq_stop(struct seq_file *seq, void *v) mddev_put(mddev); } +struct mdstat_info { + int event; +}; + static int md_seq_show(struct seq_file *seq, void *v) { mddev_t *mddev = v; sector_t sectors; mdk_rdev_t *rdev; + struct mdstat_info *mi = seq->private; struct bitmap *bitmap; if (v == (void*)1) { @@ -6410,7 +6415,7 @@ static int md_seq_show(struct seq_file *seq, void *v) spin_unlock(&pers_lock); seq_printf(seq, "\n"); - seq->poll_event = atomic_read(&md_event_count); + mi->event = atomic_read(&md_event_count); return 0; } if (v == (void*)2) { @@ -6522,21 +6527,26 @@ static const struct seq_operations md_seq_ops = { static int md_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; int error; + struct mdstat_info *mi = kmalloc(sizeof(*mi), GFP_KERNEL); + if (mi == NULL) + return -ENOMEM; error = seq_open(file, &md_seq_ops); if (error) - return error; - - seq = file->private_data; - seq->poll_event = atomic_read(&md_event_count); + kfree(mi); + else { + struct seq_file *p = file->private_data; + p->private = mi; + mi->event = atomic_read(&md_event_count); + } return error; } static unsigned int mdstat_poll(struct file *filp, poll_table *wait) { - struct seq_file *seq = filp->private_data; + struct seq_file *m = filp->private_data; + struct mdstat_info *mi = m->private; int mask; poll_wait(filp, &md_event_waiters, wait); @@ -6544,7 +6554,7 @@ static unsigned int mdstat_poll(struct file *filp, poll_table *wait) /* always allow read */ mask = POLLIN | POLLRDNORM; - if (seq->poll_event != atomic_read(&md_event_count)) + if (mi->event != atomic_read(&md_event_count)) mask |= POLLERR | POLLPRI; return mask; } diff --git a/trunk/drivers/mtd/ubi/cdev.c b/trunk/drivers/mtd/ubi/cdev.c index 3320a50ba4f0..191f3bb3c41a 100644 --- a/trunk/drivers/mtd/ubi/cdev.c +++ b/trunk/drivers/mtd/ubi/cdev.c @@ -189,16 +189,12 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin) return new_offset; } -static int vol_cdev_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int vol_cdev_fsync(struct file *file, int datasync) { struct ubi_volume_desc *desc = file->private_data; struct ubi_device *ubi = desc->vol->ubi; - struct inode *inode = file->f_path.dentry->d_inode; - int err; - mutex_lock(&inode->i_mutex); - err = ubi_sync(ubi->ubi_num); - mutex_unlock(&inode->i_mutex); - return err; + + return ubi_sync(ubi->ubi_num); } diff --git a/trunk/drivers/regulator/Kconfig b/trunk/drivers/regulator/Kconfig index 118eb213eb3a..d7ed20f293d7 100644 --- a/trunk/drivers/regulator/Kconfig +++ b/trunk/drivers/regulator/Kconfig @@ -235,7 +235,6 @@ config REGULATOR_TPS6105X config REGULATOR_TPS65023 tristate "TI TPS65023 Power regulators" depends on I2C - select REGMAP_I2C help This driver supports TPS65023 voltage regulator chips. TPS65023 provides three step-down converters and two general-purpose LDO voltage regulators. diff --git a/trunk/drivers/regulator/tps65023-regulator.c b/trunk/drivers/regulator/tps65023-regulator.c index 701a5900f83f..fbddc15e1811 100644 --- a/trunk/drivers/regulator/tps65023-regulator.c +++ b/trunk/drivers/regulator/tps65023-regulator.c @@ -25,7 +25,6 @@ #include #include #include -#include /* Register definitions */ #define TPS65023_REG_VERSION 0 @@ -126,35 +125,93 @@ struct tps_pmic { struct i2c_client *client; struct regulator_dev *rdev[TPS65023_NUM_REGULATOR]; const struct tps_info *info[TPS65023_NUM_REGULATOR]; - struct regmap *regmap; + struct mutex io_lock; }; +static inline int tps_65023_read(struct tps_pmic *tps, u8 reg) +{ + return i2c_smbus_read_byte_data(tps->client, reg); +} + +static inline int tps_65023_write(struct tps_pmic *tps, u8 reg, u8 val) +{ + return i2c_smbus_write_byte_data(tps->client, reg, val); +} + static int tps_65023_set_bits(struct tps_pmic *tps, u8 reg, u8 mask) { - return regmap_update_bits(tps->regmap, reg, mask, mask); + int err, data; + + mutex_lock(&tps->io_lock); + + data = tps_65023_read(tps, reg); + if (data < 0) { + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + err = data; + goto out; + } + + data |= mask; + err = tps_65023_write(tps, reg, data); + if (err) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + +out: + mutex_unlock(&tps->io_lock); + return err; } static int tps_65023_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask) { - return regmap_update_bits(tps->regmap, reg, mask, 0); + int err, data; + + mutex_lock(&tps->io_lock); + + data = tps_65023_read(tps, reg); + if (data < 0) { + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + err = data; + goto out; + } + + data &= ~mask; + + err = tps_65023_write(tps, reg, data); + if (err) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + +out: + mutex_unlock(&tps->io_lock); + return err; + } static int tps_65023_reg_read(struct tps_pmic *tps, u8 reg) { - unsigned int val; - int ret; + int data; - ret = regmap_read(tps->regmap, reg, &val); + mutex_lock(&tps->io_lock); - if (ret != 0) - return ret; - else - return val; + data = tps_65023_read(tps, reg); + if (data < 0) + dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); + + mutex_unlock(&tps->io_lock); + return data; } static int tps_65023_reg_write(struct tps_pmic *tps, u8 reg, u8 val) { - return regmap_write(tps->regmap, reg, val); + int err; + + mutex_lock(&tps->io_lock); + + err = tps_65023_write(tps, reg, val); + if (err < 0) + dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); + + mutex_unlock(&tps->io_lock); + return err; } static int tps65023_dcdc_is_enabled(struct regulator_dev *dev) @@ -406,11 +463,6 @@ static struct regulator_ops tps65023_ldo_ops = { .list_voltage = tps65023_ldo_list_voltage, }; -static struct regmap_config tps65023_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - static int __devinit tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -436,13 +488,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client, if (!tps) return -ENOMEM; - tps->regmap = regmap_init_i2c(client, &tps65023_regmap_config); - if (IS_ERR(tps->regmap)) { - error = PTR_ERR(tps->regmap); - dev_err(&client->dev, "Failed to allocate register map: %d\n", - error); - goto fail_alloc; - } + mutex_init(&tps->io_lock); /* common for all regulators */ tps->client = client; @@ -481,8 +527,6 @@ static int __devinit tps_65023_probe(struct i2c_client *client, while (--i >= 0) regulator_unregister(tps->rdev[i]); - regmap_exit(tps->regmap); - fail_alloc: kfree(tps); return error; } @@ -501,7 +545,6 @@ static int __devexit tps_65023_remove(struct i2c_client *client) for (i = 0; i < TPS65023_NUM_REGULATOR; i++) regulator_unregister(tps->rdev[i]); - regmap_exit(tps->regmap); kfree(tps); return 0; diff --git a/trunk/drivers/scsi/aha152x.c b/trunk/drivers/scsi/aha152x.c index f17c92cf808b..c5169f01c1cd 100644 --- a/trunk/drivers/scsi/aha152x.c +++ b/trunk/drivers/scsi/aha152x.c @@ -422,19 +422,10 @@ MODULE_PARM_DESC(aha152x1, "parameters for second controller"); #ifdef __ISAPNP__ static struct isapnp_device_id id_table[] __devinitdata = { - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1505), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1530), 0 }, { ISAPNP_DEVICE_SINGLE_END, } }; MODULE_DEVICE_TABLE(isapnp, id_table); diff --git a/trunk/drivers/scsi/atari_NCR5380.c b/trunk/drivers/scsi/atari_NCR5380.c index 2db79b469d9e..ea439f93ed81 100644 --- a/trunk/drivers/scsi/atari_NCR5380.c +++ b/trunk/drivers/scsi/atari_NCR5380.c @@ -892,11 +892,6 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags) return 0; } -static void NCR5380_exit(struct Scsi_Host *instance) -{ - /* Empty, as we didn't schedule any delayed work */ -} - /* * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, * void (*done)(Scsi_Cmnd *)) @@ -919,6 +914,7 @@ static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { SETUP_HOSTDATA(cmd->device->host); Scsi_Cmnd *tmp; + int oldto; unsigned long flags; #if (NDEBUG & NDEBUG_NO_WRITE) diff --git a/trunk/drivers/scsi/atari_scsi.c b/trunk/drivers/scsi/atari_scsi.c index 04a154f87e3e..3e8658e2f154 100644 --- a/trunk/drivers/scsi/atari_scsi.c +++ b/trunk/drivers/scsi/atari_scsi.c @@ -730,7 +730,6 @@ int atari_scsi_release(struct Scsi_Host *sh) free_irq(IRQ_TT_MFP_SCSI, sh); if (atari_dma_buffer) atari_stram_free(atari_dma_buffer); - NCR5380_exit(sh); return 1; } diff --git a/trunk/drivers/scsi/be2iscsi/be_main.c b/trunk/drivers/scsi/be2iscsi/be_main.c index 0a9bdfa3d939..94b9a07845d5 100644 --- a/trunk/drivers/scsi/be2iscsi/be_main.c +++ b/trunk/drivers/scsi/be2iscsi/be_main.c @@ -215,62 +215,73 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) { struct beiscsi_hba *phba = data; - struct mgmt_session_info *boot_sess = &phba->boot_sess; - struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0]; char *str = buf; int rc; switch (type) { case ISCSI_BOOT_TGT_NAME: rc = sprintf(buf, "%.*s\n", - (int)strlen(boot_sess->target_name), - (char *)&boot_sess->target_name); + (int)strlen(phba->boot_sess.target_name), + (char *)&phba->boot_sess.target_name); break; case ISCSI_BOOT_TGT_IP_ADDR: - if (boot_conn->dest_ipaddr.ip_type == 0x1) + if (phba->boot_sess.conn_list[0].dest_ipaddr.ip_type == 0x1) rc = sprintf(buf, "%pI4\n", - (char *)&boot_conn->dest_ipaddr.ip_address); + (char *)&phba->boot_sess.conn_list[0]. + dest_ipaddr.ip_address); else rc = sprintf(str, "%pI6\n", - (char *)&boot_conn->dest_ipaddr.ip_address); + (char *)&phba->boot_sess.conn_list[0]. + dest_ipaddr.ip_address); break; case ISCSI_BOOT_TGT_PORT: - rc = sprintf(str, "%d\n", boot_conn->dest_port); + rc = sprintf(str, "%d\n", phba->boot_sess.conn_list[0]. + dest_port); break; case ISCSI_BOOT_TGT_CHAP_NAME: rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - target_chap_name_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.target_chap_name); + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_chap_name_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_chap_name); break; case ISCSI_BOOT_TGT_CHAP_SECRET: rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - target_secret_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.target_secret); + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_secret_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_secret); + break; case ISCSI_BOOT_TGT_REV_CHAP_NAME: rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - intr_chap_name_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.intr_chap_name); + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_chap_name_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_chap_name); + break; case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - intr_secret_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.intr_secret); + rc = sprintf(str, "%.*s\n", + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_secret_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_secret); break; case ISCSI_BOOT_TGT_FLAGS: - rc = sprintf(str, "2\n"); + rc = sprintf(str, "2\n"); break; case ISCSI_BOOT_TGT_NIC_ASSOC: - rc = sprintf(str, "0\n"); + rc = sprintf(str, "0\n"); break; default: rc = -ENOSYS; @@ -304,10 +315,10 @@ static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) switch (type) { case ISCSI_BOOT_ETH_FLAGS: - rc = sprintf(str, "2\n"); + rc = sprintf(str, "2\n"); break; case ISCSI_BOOT_ETH_INDEX: - rc = sprintf(str, "0\n"); + rc = sprintf(str, "0\n"); break; case ISCSI_BOOT_ETH_MAC: rc = beiscsi_get_macaddr(buf, phba); @@ -380,6 +391,40 @@ static mode_t beiscsi_eth_get_attr_visibility(void *data, int type) return rc; } +static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) +{ + struct iscsi_boot_kobj *boot_kobj; + + phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); + if (!phba->boot_kset) + return -ENOMEM; + + /* get boot info using mgmt cmd */ + boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba, + beiscsi_show_boot_tgt_info, + beiscsi_tgt_get_attr_visibility); + if (!boot_kobj) + goto free_kset; + + boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba, + beiscsi_show_boot_ini_info, + beiscsi_ini_get_attr_visibility); + if (!boot_kobj) + goto free_kset; + + boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba, + beiscsi_show_boot_eth_info, + beiscsi_eth_get_attr_visibility); + if (!boot_kobj) + goto free_kset; + return 0; + +free_kset: + if (phba->boot_kset) + iscsi_boot_destroy_kset(phba->boot_kset); + return -ENOMEM; +} + /*------------------- PCI Driver operations and data ----------------- */ static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = { { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, @@ -438,6 +483,14 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) if (iscsi_host_add(shost, &phba->pcidev->dev)) goto free_devices; + if (beiscsi_setup_boot_info(phba)) + /* + * log error but continue, because we may not be using + * iscsi boot. + */ + shost_printk(KERN_ERR, phba->shost, "Could not set up " + "iSCSI boot info."); + return phba; free_devices: @@ -3458,7 +3511,6 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) unsigned int tag, wrb_num; unsigned short status, extd_status; struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; - int ret = -ENOMEM; tag = beiscsi_get_boot_target(phba); if (!tag) { @@ -3483,7 +3535,8 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) boot_resp = embedded_payload(wrb); if (boot_resp->boot_session_handle < 0) { - shost_printk(KERN_INFO, phba->shost, "No Boot Session.\n"); + printk(KERN_ERR "No Boot Session for this pci_func," + "session Hndl = %d\n", boot_resp->boot_session_handle); return -ENXIO; } @@ -3521,70 +3574,14 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) wrb = queue_get_wrb(mccq, wrb_num); free_mcc_tag(&phba->ctrl, tag); session_resp = nonemb_cmd.va ; - memcpy(&phba->boot_sess, &session_resp->session_info, sizeof(struct mgmt_session_info)); - ret = 0; - -boot_freemem: pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); - return ret; -} - -static void beiscsi_boot_release(void *data) -{ - struct beiscsi_hba *phba = data; - - scsi_host_put(phba->shost); -} - -static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) -{ - struct iscsi_boot_kobj *boot_kobj; - - /* get boot info using mgmt cmd */ - if (beiscsi_get_boot_info(phba)) - /* Try to see if we can carry on without this */ - return 0; - - phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); - if (!phba->boot_kset) - return -ENOMEM; - - /* get a ref because the show function will ref the phba */ - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba, - beiscsi_show_boot_tgt_info, - beiscsi_tgt_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba, - beiscsi_show_boot_ini_info, - beiscsi_ini_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba, - beiscsi_show_boot_eth_info, - beiscsi_eth_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; return 0; - -put_shost: - scsi_host_put(phba->shost); -free_kset: - iscsi_boot_destroy_kset(phba->boot_kset); +boot_freemem: + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); return -ENOMEM; } @@ -3966,10 +3963,11 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, } memcpy(&io_task->cmd_bhs->iscsi_data_pdu. dw[offsetof(struct amap_pdu_data_out, lun) / 32], - &io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun)); + io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun)); AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb, - cpu_to_be16(*(unsigned short *)&io_task->cmd_bhs->iscsi_hdr.lun)); + cpu_to_be16((unsigned short)io_task->cmd_bhs->iscsi_hdr. + lun[0])); AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, xferlen); AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, io_task->pwrb_handle->wrb_index); @@ -4152,7 +4150,8 @@ static void beiscsi_remove(struct pci_dev *pcidev) phba->ctrl.mbox_mem_alloced.size, phba->ctrl.mbox_mem_alloced.va, phba->ctrl.mbox_mem_alloced.dma); - iscsi_boot_destroy_kset(phba->boot_kset); + if (phba->boot_kset) + iscsi_boot_destroy_kset(phba->boot_kset); iscsi_host_remove(phba->shost); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); @@ -4311,15 +4310,11 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, goto free_blkenbld; } hwi_enable_intr(phba); - - if (beiscsi_setup_boot_info(phba)) - /* - * log error but continue, because we may not be using - * iscsi boot. - */ - shost_printk(KERN_ERR, phba->shost, "Could not set up " - "iSCSI boot info."); - + ret = beiscsi_get_boot_info(phba); + if (ret < 0) { + shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" + "No Boot Devices !!!!!\n"); + } SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n"); return 0; diff --git a/trunk/drivers/scsi/bfa/Makefile b/trunk/drivers/scsi/bfa/Makefile index 475cf925d5e8..4ce6f4942327 100644 --- a/trunk/drivers/scsi/bfa/Makefile +++ b/trunk/drivers/scsi/bfa/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_SCSI_BFA_FC) := bfa.o -bfa-y := bfad.o bfad_im.o bfad_attr.o bfad_debugfs.o bfad_bsg.o +bfa-y := bfad.o bfad_im.o bfad_attr.o bfad_debugfs.o bfa-y += bfa_ioc.o bfa_ioc_cb.o bfa_ioc_ct.o bfa_hw_cb.o bfa_hw_ct.o bfa-y += bfa_fcs.o bfa_fcs_lport.o bfa_fcs_rport.o bfa_fcs_fcpim.o bfa_fcbuild.o bfa-y += bfa_port.o bfa_fcpim.o bfa_core.o bfa_svc.o diff --git a/trunk/drivers/scsi/bfa/bfa.h b/trunk/drivers/scsi/bfa/bfa.h index 3b0af1102bf4..7be6b5a8114b 100644 --- a/trunk/drivers/scsi/bfa/bfa.h +++ b/trunk/drivers/scsi/bfa/bfa.h @@ -27,6 +27,7 @@ struct bfa_s; typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m); +typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); /* * Interrupt message handlers @@ -53,8 +54,7 @@ void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m); ((void *)((struct bfi_msg_s *)((__bfa)->iocfc.req_cq_ba[__reqq].kva) \ + bfa_reqq_pi((__bfa), (__reqq))))) -#define bfa_reqq_produce(__bfa, __reqq, __mh) do { \ - (__mh).mtag.h2i.qid = (__bfa)->iocfc.hw_qid[__reqq];\ +#define bfa_reqq_produce(__bfa, __reqq) do { \ (__bfa)->iocfc.req_cq_pi[__reqq]++; \ (__bfa)->iocfc.req_cq_pi[__reqq] &= \ ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \ @@ -75,6 +75,16 @@ void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m); (__index) &= ((__size) - 1); \ } while (0) +/* + * Queue element to wait for room in request queue. FIFO order is + * maintained when fullfilling requests. + */ +struct bfa_reqq_wait_s { + struct list_head qe; + void (*qresume) (void *cbarg); + void *cbarg; +}; + /* * Circular queue usage assignments */ @@ -118,6 +128,18 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg), #define bfa_reqq_wcancel(__wqe) list_del(&(__wqe)->qe) + +/* + * Generic BFA callback element. + */ +struct bfa_cb_qe_s { + struct list_head qe; + bfa_cb_cbfn_t cbfn; + bfa_boolean_t once; + u32 rsvd; + void *cbarg; +}; + #define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do { \ (__hcb_qe)->cbfn = (__cbfn); \ (__hcb_qe)->cbarg = (__cbarg); \ @@ -150,14 +172,44 @@ struct bfa_pciid_s { extern char bfa_version[]; +/* + * BFA memory resources + */ +enum bfa_mem_type { + BFA_MEM_TYPE_KVA = 1, /* Kernel Virtual Memory *(non-dma-able) */ + BFA_MEM_TYPE_DMA = 2, /* DMA-able memory */ + BFA_MEM_TYPE_MAX = BFA_MEM_TYPE_DMA, +}; + +struct bfa_mem_elem_s { + enum bfa_mem_type mem_type; /* see enum bfa_mem_type */ + u32 mem_len; /* Total Length in Bytes */ + u8 *kva; /* kernel virtual address */ + u64 dma; /* dma address if DMA memory */ + u8 *kva_curp; /* kva allocation cursor */ + u64 dma_curp; /* dma allocation cursor */ +}; + +struct bfa_meminfo_s { + struct bfa_mem_elem_s meminfo[BFA_MEM_TYPE_MAX]; +}; +#define bfa_meminfo_kva(_m) \ + ((_m)->meminfo[BFA_MEM_TYPE_KVA - 1].kva_curp) +#define bfa_meminfo_dma_virt(_m) \ + ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp) +#define bfa_meminfo_dma_phys(_m) \ + ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp) + struct bfa_iocfc_regs_s { void __iomem *intr_status; void __iomem *intr_mask; void __iomem *cpe_q_pi[BFI_IOC_MAX_CQS]; void __iomem *cpe_q_ci[BFI_IOC_MAX_CQS]; + void __iomem *cpe_q_depth[BFI_IOC_MAX_CQS]; void __iomem *cpe_q_ctrl[BFI_IOC_MAX_CQS]; void __iomem *rme_q_ci[BFI_IOC_MAX_CQS]; void __iomem *rme_q_pi[BFI_IOC_MAX_CQS]; + void __iomem *rme_q_depth[BFI_IOC_MAX_CQS]; void __iomem *rme_q_ctrl[BFI_IOC_MAX_CQS]; }; @@ -179,55 +231,25 @@ struct bfa_hwif_s { void (*hw_reqq_ack)(struct bfa_s *bfa, int reqq); void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq); void (*hw_msix_init)(struct bfa_s *bfa, int nvecs); - void (*hw_msix_ctrl_install)(struct bfa_s *bfa); - void (*hw_msix_queue_install)(struct bfa_s *bfa); + void (*hw_msix_install)(struct bfa_s *bfa); void (*hw_msix_uninstall)(struct bfa_s *bfa); void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix); void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, u32 *maxvec); void (*hw_msix_get_rme_range) (struct bfa_s *bfa, u32 *start, u32 *end); - int cpe_vec_q0; - int rme_vec_q0; }; typedef void (*bfa_cb_iocfc_t) (void *cbarg, enum bfa_status status); -struct bfa_faa_cbfn_s { - bfa_cb_iocfc_t faa_cbfn; - void *faa_cbarg; -}; - -#define BFA_FAA_ENABLED 1 -#define BFA_FAA_DISABLED 2 - -/* - * FAA attributes - */ -struct bfa_faa_attr_s { - wwn_t faa; - u8 faa_state; - u8 pwwn_source; - u8 rsvd[6]; -}; - -struct bfa_faa_args_s { - struct bfa_faa_attr_s *faa_attr; - struct bfa_faa_cbfn_s faa_cb; - u8 faa_state; - bfa_boolean_t busy; -}; - struct bfa_iocfc_s { struct bfa_s *bfa; struct bfa_iocfc_cfg_s cfg; int action; u32 req_cq_pi[BFI_IOC_MAX_CQS]; u32 rsp_cq_ci[BFI_IOC_MAX_CQS]; - u8 hw_qid[BFI_IOC_MAX_CQS]; struct bfa_cb_qe_s init_hcb_qe; struct bfa_cb_qe_s stop_hcb_qe; struct bfa_cb_qe_s dis_hcb_qe; - struct bfa_cb_qe_s en_hcb_qe; struct bfa_cb_qe_s stats_hcb_qe; bfa_boolean_t cfgdone; @@ -235,6 +257,7 @@ struct bfa_iocfc_s { struct bfi_iocfc_cfg_s *cfginfo; struct bfa_dma_s cfgrsp_dma; struct bfi_iocfc_cfgrsp_s *cfgrsp; + struct bfi_iocfc_cfg_reply_s *cfg_reply; struct bfa_dma_s req_cq_ba[BFI_IOC_MAX_CQS]; struct bfa_dma_s req_cq_shadow_ci[BFI_IOC_MAX_CQS]; struct bfa_dma_s rsp_cq_ba[BFI_IOC_MAX_CQS]; @@ -244,42 +267,18 @@ struct bfa_iocfc_s { bfa_cb_iocfc_t updateq_cbfn; /* bios callback function */ void *updateq_cbarg; /* bios callback arg */ u32 intr_mask; - struct bfa_faa_args_s faa_args; - struct bfa_mem_dma_s ioc_dma; - struct bfa_mem_dma_s iocfc_dma; - struct bfa_mem_dma_s reqq_dma[BFI_IOC_MAX_CQS]; - struct bfa_mem_dma_s rspq_dma[BFI_IOC_MAX_CQS]; - struct bfa_mem_kva_s kva_seg; }; -#define BFA_MEM_IOC_DMA(_bfa) (&((_bfa)->iocfc.ioc_dma)) -#define BFA_MEM_IOCFC_DMA(_bfa) (&((_bfa)->iocfc.iocfc_dma)) -#define BFA_MEM_REQQ_DMA(_bfa, _qno) (&((_bfa)->iocfc.reqq_dma[(_qno)])) -#define BFA_MEM_RSPQ_DMA(_bfa, _qno) (&((_bfa)->iocfc.rspq_dma[(_qno)])) -#define BFA_MEM_IOCFC_KVA(_bfa) (&((_bfa)->iocfc.kva_seg)) - -#define bfa_fn_lpu(__bfa) \ - bfi_fn_lpu(bfa_ioc_pcifn(&(__bfa)->ioc), bfa_ioc_portid(&(__bfa)->ioc)) +#define bfa_lpuid(__bfa) \ + bfa_ioc_portid(&(__bfa)->ioc) #define bfa_msix_init(__bfa, __nvecs) \ ((__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs)) -#define bfa_msix_ctrl_install(__bfa) \ - ((__bfa)->iocfc.hwif.hw_msix_ctrl_install(__bfa)) -#define bfa_msix_queue_install(__bfa) \ - ((__bfa)->iocfc.hwif.hw_msix_queue_install(__bfa)) +#define bfa_msix_install(__bfa) \ + ((__bfa)->iocfc.hwif.hw_msix_install(__bfa)) #define bfa_msix_uninstall(__bfa) \ ((__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa)) -#define bfa_isr_rspq_ack(__bfa, __queue) do { \ - if ((__bfa)->iocfc.hwif.hw_rspq_ack) \ - (__bfa)->iocfc.hwif.hw_rspq_ack(__bfa, __queue); \ -} while (0) -#define bfa_isr_reqq_ack(__bfa, __queue) do { \ - if ((__bfa)->iocfc.hwif.hw_reqq_ack) \ - (__bfa)->iocfc.hwif.hw_reqq_ack(__bfa, __queue); \ -} while (0) -#define bfa_isr_mode_set(__bfa, __msix) do { \ - if ((__bfa)->iocfc.hwif.hw_isr_mode_set) \ - (__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix); \ -} while (0) +#define bfa_isr_mode_set(__bfa, __msix) \ + ((__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix)) #define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \ ((__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, \ __nvecs, __maxvec)) @@ -291,17 +290,17 @@ struct bfa_iocfc_s { /* * FC specific IOC functions. */ -void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa); +void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len); void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev); void bfa_iocfc_init(struct bfa_s *bfa); void bfa_iocfc_start(struct bfa_s *bfa); void bfa_iocfc_stop(struct bfa_s *bfa); void bfa_iocfc_isr(void *bfa, struct bfi_mbmsg_s *msg); -void bfa_iocfc_set_snsbase(struct bfa_s *bfa, int seg_no, u64 snsbase_pa); +void bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa); bfa_boolean_t bfa_iocfc_is_operational(struct bfa_s *bfa); void bfa_iocfc_reset_queues(struct bfa_s *bfa); @@ -311,10 +310,10 @@ void bfa_msix_rspq(struct bfa_s *bfa, int vec); void bfa_msix_lpu_err(struct bfa_s *bfa, int vec); void bfa_hwcb_reginit(struct bfa_s *bfa); +void bfa_hwcb_reqq_ack(struct bfa_s *bfa, int rspq); void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq); void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs); -void bfa_hwcb_msix_ctrl_install(struct bfa_s *bfa); -void bfa_hwcb_msix_queue_install(struct bfa_s *bfa); +void bfa_hwcb_msix_install(struct bfa_s *bfa); void bfa_hwcb_msix_uninstall(struct bfa_s *bfa); void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, @@ -322,12 +321,10 @@ void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, void bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end); void bfa_hwct_reginit(struct bfa_s *bfa); -void bfa_hwct2_reginit(struct bfa_s *bfa); void bfa_hwct_reqq_ack(struct bfa_s *bfa, int rspq); void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq); void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs); -void bfa_hwct_msix_ctrl_install(struct bfa_s *bfa); -void bfa_hwct_msix_queue_install(struct bfa_s *bfa); +void bfa_hwct_msix_install(struct bfa_s *bfa); void bfa_hwct_msix_uninstall(struct bfa_s *bfa); void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, @@ -380,8 +377,7 @@ void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids); void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg); void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg); void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa); + struct bfa_meminfo_s *meminfo); void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev); diff --git a/trunk/drivers/scsi/bfa/bfa_core.c b/trunk/drivers/scsi/bfa/bfa_core.c index c38e589105a5..91838c51fb76 100644 --- a/trunk/drivers/scsi/bfa/bfa_core.c +++ b/trunk/drivers/scsi/bfa/bfa_core.c @@ -17,7 +17,7 @@ #include "bfad_drv.h" #include "bfa_modules.h" -#include "bfi_reg.h" +#include "bfi_ctreg.h" BFA_TRC_FILE(HAL, CORE); @@ -25,14 +25,13 @@ BFA_TRC_FILE(HAL, CORE); * BFA module list terminated by NULL */ static struct bfa_module_s *hal_mods[] = { - &hal_mod_fcdiag, &hal_mod_sgpg, &hal_mod_fcport, &hal_mod_fcxp, &hal_mod_lps, &hal_mod_uf, &hal_mod_rport, - &hal_mod_fcp, + &hal_mod_fcpim, NULL }; @@ -42,7 +41,7 @@ static struct bfa_module_s *hal_mods[] = { static bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = { bfa_isr_unhandled, /* NONE */ bfa_isr_unhandled, /* BFI_MC_IOC */ - bfa_fcdiag_intr, /* BFI_MC_DIAG */ + bfa_isr_unhandled, /* BFI_MC_DIAG */ bfa_isr_unhandled, /* BFI_MC_FLASH */ bfa_isr_unhandled, /* BFI_MC_CEE */ bfa_fcport_isr, /* BFI_MC_FCPORT */ @@ -52,7 +51,7 @@ static bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = { bfa_fcxp_isr, /* BFI_MC_FCXP */ bfa_lps_isr, /* BFI_MC_LPS */ bfa_rport_isr, /* BFI_MC_RPORT */ - bfa_itn_isr, /* BFI_MC_ITN */ + bfa_itnim_isr, /* BFI_MC_ITNIM */ bfa_isr_unhandled, /* BFI_MC_IOIM_READ */ bfa_isr_unhandled, /* BFI_MC_IOIM_WRITE */ bfa_isr_unhandled, /* BFI_MC_IOIM_IO */ @@ -90,78 +89,23 @@ static bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = { static void -bfa_com_port_attach(struct bfa_s *bfa) +bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi) { struct bfa_port_s *port = &bfa->modules.port; - struct bfa_mem_dma_s *port_dma = BFA_MEM_PORT_DMA(bfa); + u32 dm_len; + u8 *dm_kva; + u64 dm_pa; - bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod); - bfa_port_mem_claim(port, port_dma->kva_curp, port_dma->dma_curp); -} - -/* - * ablk module attach - */ -static void -bfa_com_ablk_attach(struct bfa_s *bfa) -{ - struct bfa_ablk_s *ablk = &bfa->modules.ablk; - struct bfa_mem_dma_s *ablk_dma = BFA_MEM_ABLK_DMA(bfa); - - bfa_ablk_attach(ablk, &bfa->ioc); - bfa_ablk_memclaim(ablk, ablk_dma->kva_curp, ablk_dma->dma_curp); -} - -static void -bfa_com_cee_attach(struct bfa_s *bfa) -{ - struct bfa_cee_s *cee = &bfa->modules.cee; - struct bfa_mem_dma_s *cee_dma = BFA_MEM_CEE_DMA(bfa); - - cee->trcmod = bfa->trcmod; - bfa_cee_attach(cee, &bfa->ioc, bfa); - bfa_cee_mem_claim(cee, cee_dma->kva_curp, cee_dma->dma_curp); -} - -static void -bfa_com_sfp_attach(struct bfa_s *bfa) -{ - struct bfa_sfp_s *sfp = BFA_SFP_MOD(bfa); - struct bfa_mem_dma_s *sfp_dma = BFA_MEM_SFP_DMA(bfa); - - bfa_sfp_attach(sfp, &bfa->ioc, bfa, bfa->trcmod); - bfa_sfp_memclaim(sfp, sfp_dma->kva_curp, sfp_dma->dma_curp); -} - -static void -bfa_com_flash_attach(struct bfa_s *bfa, bfa_boolean_t mincfg) -{ - struct bfa_flash_s *flash = BFA_FLASH(bfa); - struct bfa_mem_dma_s *flash_dma = BFA_MEM_FLASH_DMA(bfa); - - bfa_flash_attach(flash, &bfa->ioc, bfa, bfa->trcmod, mincfg); - bfa_flash_memclaim(flash, flash_dma->kva_curp, - flash_dma->dma_curp, mincfg); -} - -static void -bfa_com_diag_attach(struct bfa_s *bfa) -{ - struct bfa_diag_s *diag = BFA_DIAG_MOD(bfa); - struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa); + dm_len = bfa_port_meminfo(); + dm_kva = bfa_meminfo_dma_virt(mi); + dm_pa = bfa_meminfo_dma_phys(mi); - bfa_diag_attach(diag, &bfa->ioc, bfa, bfa_fcport_beacon, bfa->trcmod); - bfa_diag_memclaim(diag, diag_dma->kva_curp, diag_dma->dma_curp); -} - -static void -bfa_com_phy_attach(struct bfa_s *bfa, bfa_boolean_t mincfg) -{ - struct bfa_phy_s *phy = BFA_PHY(bfa); - struct bfa_mem_dma_s *phy_dma = BFA_MEM_PHY_DMA(bfa); + memset(port, 0, sizeof(struct bfa_port_s)); + bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod); + bfa_port_mem_claim(port, dm_kva, dm_pa); - bfa_phy_attach(phy, &bfa->ioc, bfa, bfa->trcmod, mincfg); - bfa_phy_memclaim(phy, phy_dma->kva_curp, phy_dma->dma_curp, mincfg); + bfa_meminfo_dma_virt(mi) = dm_kva + dm_len; + bfa_meminfo_dma_phys(mi) = dm_pa + dm_len; } /* @@ -178,7 +122,6 @@ enum { BFA_IOCFC_ACT_INIT = 1, BFA_IOCFC_ACT_STOP = 2, BFA_IOCFC_ACT_DISABLE = 3, - BFA_IOCFC_ACT_ENABLE = 4, }; #define DEF_CFG_NUM_FABRICS 1 @@ -230,92 +173,10 @@ bfa_reqq_resume(struct bfa_s *bfa, int qid) } } -static inline void -bfa_isr_rspq(struct bfa_s *bfa, int qid) -{ - struct bfi_msg_s *m; - u32 pi, ci; - struct list_head *waitq; - - bfa_isr_rspq_ack(bfa, qid); - - ci = bfa_rspq_ci(bfa, qid); - pi = bfa_rspq_pi(bfa, qid); - - while (ci != pi) { - m = bfa_rspq_elem(bfa, qid, ci); - WARN_ON(m->mhdr.msg_class >= BFI_MC_MAX); - - bfa_isrs[m->mhdr.msg_class] (bfa, m); - CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems); - } - - /* - * update CI - */ - bfa_rspq_ci(bfa, qid) = pi; - writel(pi, bfa->iocfc.bfa_regs.rme_q_ci[qid]); - mmiowb(); - - /* - * Resume any pending requests in the corresponding reqq. - */ - waitq = bfa_reqq(bfa, qid); - if (!list_empty(waitq)) - bfa_reqq_resume(bfa, qid); -} - -static inline void -bfa_isr_reqq(struct bfa_s *bfa, int qid) -{ - struct list_head *waitq; - - bfa_isr_reqq_ack(bfa, qid); - - /* - * Resume any pending requests in the corresponding reqq. - */ - waitq = bfa_reqq(bfa, qid); - if (!list_empty(waitq)) - bfa_reqq_resume(bfa, qid); -} - void bfa_msix_all(struct bfa_s *bfa, int vec) { - u32 intr, qintr; - int queue; - - intr = readl(bfa->iocfc.bfa_regs.intr_status); - if (!intr) - return; - - /* - * RME completion queue interrupt - */ - qintr = intr & __HFN_INT_RME_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_rspq(bfa, queue); - } - - intr &= ~qintr; - if (!intr) - return; - - /* - * CPE completion queue interrupt - */ - qintr = intr & __HFN_INT_CPE_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_reqq(bfa, queue); - } - intr &= ~qintr; - if (!intr) - return; - - bfa_msix_lpu_err(bfa, intr); + bfa_intx(bfa); } bfa_boolean_t @@ -328,19 +189,16 @@ bfa_intx(struct bfa_s *bfa) if (!intr) return BFA_FALSE; - qintr = intr & (__HFN_INT_RME_MASK | __HFN_INT_CPE_MASK); - if (qintr) - writel(qintr, bfa->iocfc.bfa_regs.intr_status); - /* * RME completion queue interrupt */ qintr = intr & __HFN_INT_RME_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_rspq(bfa, queue); - } + writel(qintr, bfa->iocfc.bfa_regs.intr_status); + for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) { + if (intr & (__HFN_INT_RME_Q0 << queue)) + bfa_msix_rspq(bfa, queue & (BFI_IOC_MAX_CQS - 1)); + } intr &= ~qintr; if (!intr) return BFA_TRUE; @@ -349,9 +207,11 @@ bfa_intx(struct bfa_s *bfa) * CPE completion queue interrupt */ qintr = intr & __HFN_INT_CPE_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_reqq(bfa, queue); + writel(qintr, bfa->iocfc.bfa_regs.intr_status); + + for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) { + if (intr & (__HFN_INT_CPE_Q0 << queue)) + bfa_msix_reqq(bfa, queue & (BFI_IOC_MAX_CQS - 1)); } intr &= ~qintr; if (!intr) @@ -365,25 +225,32 @@ bfa_intx(struct bfa_s *bfa) void bfa_isr_enable(struct bfa_s *bfa) { - u32 umsk; + u32 intr_unmask; int pci_func = bfa_ioc_pcifn(&bfa->ioc); bfa_trc(bfa, pci_func); - bfa_msix_ctrl_install(bfa); - - if (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id)) { - umsk = __HFN_INT_ERR_MASK_CT2; - umsk |= pci_func == 0 ? - __HFN_INT_FN0_MASK_CT2 : __HFN_INT_FN1_MASK_CT2; - } else { - umsk = __HFN_INT_ERR_MASK; - umsk |= pci_func == 0 ? __HFN_INT_FN0_MASK : __HFN_INT_FN1_MASK; - } - - writel(umsk, bfa->iocfc.bfa_regs.intr_status); - writel(~umsk, bfa->iocfc.bfa_regs.intr_mask); - bfa->iocfc.intr_mask = ~umsk; + bfa_msix_install(bfa); + intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | + __HFN_INT_LL_HALT); + + if (pci_func == 0) + intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | + __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 | + __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | + __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | + __HFN_INT_MBOX_LPU0); + else + intr_unmask |= (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | + __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 | + __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | + __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | + __HFN_INT_MBOX_LPU1); + + writel(intr_unmask, bfa->iocfc.bfa_regs.intr_status); + writel(~intr_unmask, bfa->iocfc.bfa_regs.intr_mask); + bfa->iocfc.intr_mask = ~intr_unmask; bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0); } @@ -396,9 +263,20 @@ bfa_isr_disable(struct bfa_s *bfa) } void -bfa_msix_reqq(struct bfa_s *bfa, int vec) +bfa_msix_reqq(struct bfa_s *bfa, int qid) { - bfa_isr_reqq(bfa, vec - bfa->iocfc.hwif.cpe_vec_q0); + struct list_head *waitq; + + qid &= (BFI_IOC_MAX_CQS - 1); + + bfa->iocfc.hwif.hw_reqq_ack(bfa, qid); + + /* + * Resume any pending requests in the corresponding reqq. + */ + waitq = bfa_reqq(bfa, qid); + if (!list_empty(waitq)) + bfa_reqq_resume(bfa, qid); } void @@ -412,37 +290,57 @@ bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m) } void -bfa_msix_rspq(struct bfa_s *bfa, int vec) +bfa_msix_rspq(struct bfa_s *bfa, int qid) { - bfa_isr_rspq(bfa, vec - bfa->iocfc.hwif.rme_vec_q0); + struct bfi_msg_s *m; + u32 pi, ci; + struct list_head *waitq; + + qid &= (BFI_IOC_MAX_CQS - 1); + + bfa->iocfc.hwif.hw_rspq_ack(bfa, qid); + + ci = bfa_rspq_ci(bfa, qid); + pi = bfa_rspq_pi(bfa, qid); + + if (bfa->rme_process) { + while (ci != pi) { + m = bfa_rspq_elem(bfa, qid, ci); + bfa_isrs[m->mhdr.msg_class] (bfa, m); + CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems); + } + } + + /* + * update CI + */ + bfa_rspq_ci(bfa, qid) = pi; + writel(pi, bfa->iocfc.bfa_regs.rme_q_ci[qid]); + mmiowb(); + + /* + * Resume any pending requests in the corresponding reqq. + */ + waitq = bfa_reqq(bfa, qid); + if (!list_empty(waitq)) + bfa_reqq_resume(bfa, qid); } void bfa_msix_lpu_err(struct bfa_s *bfa, int vec) { u32 intr, curr_value; - bfa_boolean_t lpu_isr, halt_isr, pss_isr; intr = readl(bfa->iocfc.bfa_regs.intr_status); - if (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id)) { - halt_isr = intr & __HFN_INT_CPQ_HALT_CT2; - pss_isr = intr & __HFN_INT_ERR_PSS_CT2; - lpu_isr = intr & (__HFN_INT_MBOX_LPU0_CT2 | - __HFN_INT_MBOX_LPU1_CT2); - intr &= __HFN_INT_ERR_MASK_CT2; - } else { - halt_isr = intr & __HFN_INT_LL_HALT; - pss_isr = intr & __HFN_INT_ERR_PSS; - lpu_isr = intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1); - intr &= __HFN_INT_ERR_MASK; - } - - if (lpu_isr) + if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1)) bfa_ioc_mbox_isr(&bfa->ioc); + intr &= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT); + if (intr) { - if (halt_isr) { + if (intr & __HFN_INT_LL_HALT) { /* * If LL_HALT bit is set then FW Init Halt LL Port * Register needs to be cleared as well so Interrupt @@ -453,7 +351,7 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec) writel(curr_value, bfa->ioc.ioc_regs.ll_halt); } - if (pss_isr) { + if (intr & __HFN_INT_ERR_PSS) { /* * ERR_PSS bit needs to be cleared as well in case * interrups are shared so driver's interrupt handler is @@ -461,6 +359,7 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec) */ curr_value = readl( bfa->ioc.ioc_regs.pss_err_status_reg); + curr_value &= __PSS_ERR_STATUS_SET; writel(curr_value, bfa->ioc.ioc_regs.pss_err_status_reg); } @@ -478,6 +377,41 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec) * BFA IOC private functions */ +static void +bfa_iocfc_cqs_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) +{ + int i, per_reqq_sz, per_rspq_sz; + + per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), + BFA_DMA_ALIGN_SZ); + per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), + BFA_DMA_ALIGN_SZ); + + /* + * Calculate CQ size + */ + for (i = 0; i < cfg->fwcfg.num_cqs; i++) { + *dm_len = *dm_len + per_reqq_sz; + *dm_len = *dm_len + per_rspq_sz; + } + + /* + * Calculate Shadow CI/PI size + */ + for (i = 0; i < cfg->fwcfg.num_cqs; i++) + *dm_len += (2 * BFA_CACHELINE_SZ); +} + +static void +bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) +{ + *dm_len += + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); + *dm_len += + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), + BFA_CACHELINE_SZ); +} + /* * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ */ @@ -499,13 +433,8 @@ bfa_iocfc_send_cfg(void *bfa_arg) /* * initialize IOC configuration info */ - cfg_info->single_msix_vec = 0; - if (bfa->msix.nvecs == 1) - cfg_info->single_msix_vec = 1; cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG; cfg_info->num_cqs = cfg->fwcfg.num_cqs; - cfg_info->num_ioim_reqs = cpu_to_be16(cfg->fwcfg.num_ioim_reqs); - cfg_info->num_fwtio_reqs = cpu_to_be16(cfg->fwcfg.num_fwtio_reqs); bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa); /* @@ -540,7 +469,7 @@ bfa_iocfc_send_cfg(void *bfa_arg) * dma map IOC configuration itself */ bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ, - bfa_fn_lpu(bfa)); + bfa_lpuid(bfa)); bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa); bfa_ioc_mbox_send(&bfa->ioc, &cfg_req, @@ -562,40 +491,26 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, /* * Initialize chip specific handlers. */ - if (bfa_asic_id_ctc(bfa_ioc_devid(&bfa->ioc))) { + if (bfa_asic_id_ct(bfa_ioc_devid(&bfa->ioc))) { iocfc->hwif.hw_reginit = bfa_hwct_reginit; iocfc->hwif.hw_reqq_ack = bfa_hwct_reqq_ack; iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack; iocfc->hwif.hw_msix_init = bfa_hwct_msix_init; - iocfc->hwif.hw_msix_ctrl_install = bfa_hwct_msix_ctrl_install; - iocfc->hwif.hw_msix_queue_install = bfa_hwct_msix_queue_install; + iocfc->hwif.hw_msix_install = bfa_hwct_msix_install; iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall; iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set; iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs; iocfc->hwif.hw_msix_get_rme_range = bfa_hwct_msix_get_rme_range; - iocfc->hwif.rme_vec_q0 = BFI_MSIX_RME_QMIN_CT; - iocfc->hwif.cpe_vec_q0 = BFI_MSIX_CPE_QMIN_CT; } else { iocfc->hwif.hw_reginit = bfa_hwcb_reginit; - iocfc->hwif.hw_reqq_ack = NULL; - iocfc->hwif.hw_rspq_ack = NULL; + iocfc->hwif.hw_reqq_ack = bfa_hwcb_reqq_ack; + iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack; iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init; - iocfc->hwif.hw_msix_ctrl_install = bfa_hwcb_msix_ctrl_install; - iocfc->hwif.hw_msix_queue_install = bfa_hwcb_msix_queue_install; + iocfc->hwif.hw_msix_install = bfa_hwcb_msix_install; iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall; iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set; iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs; iocfc->hwif.hw_msix_get_rme_range = bfa_hwcb_msix_get_rme_range; - iocfc->hwif.rme_vec_q0 = BFI_MSIX_RME_QMIN_CB + - bfa_ioc_pcifn(&bfa->ioc) * BFI_IOC_MAX_CQS; - iocfc->hwif.cpe_vec_q0 = BFI_MSIX_CPE_QMIN_CB + - bfa_ioc_pcifn(&bfa->ioc) * BFI_IOC_MAX_CQS; - } - - if (bfa_asic_id_ct2(bfa_ioc_devid(&bfa->ioc))) { - iocfc->hwif.hw_reginit = bfa_hwct2_reginit; - iocfc->hwif.hw_isr_mode_set = NULL; - iocfc->hwif.hw_rspq_ack = NULL; } iocfc->hwif.hw_reginit(bfa); @@ -603,42 +518,48 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, } static void -bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg) +bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo) { - u8 *dm_kva = NULL; - u64 dm_pa = 0; - int i, per_reqq_sz, per_rspq_sz, dbgsz; + u8 *dm_kva; + u64 dm_pa; + int i, per_reqq_sz, per_rspq_sz; struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfa_mem_dma_s *ioc_dma = BFA_MEM_IOC_DMA(bfa); - struct bfa_mem_dma_s *iocfc_dma = BFA_MEM_IOCFC_DMA(bfa); - struct bfa_mem_dma_s *reqq_dma, *rspq_dma; + int dbgsz; + + dm_kva = bfa_meminfo_dma_virt(meminfo); + dm_pa = bfa_meminfo_dma_phys(meminfo); - /* First allocate dma memory for IOC */ - bfa_ioc_mem_claim(&bfa->ioc, bfa_mem_dma_virt(ioc_dma), - bfa_mem_dma_phys(ioc_dma)); + /* + * First allocate dma memory for IOC. + */ + bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa); + dm_kva += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ); + dm_pa += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ); - /* Claim DMA-able memory for the request/response queues */ + /* + * Claim DMA-able memory for the request/response queues and for shadow + * ci/pi registers + */ per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); + BFA_DMA_ALIGN_SZ); per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); + BFA_DMA_ALIGN_SZ); for (i = 0; i < cfg->fwcfg.num_cqs; i++) { - reqq_dma = BFA_MEM_REQQ_DMA(bfa, i); - iocfc->req_cq_ba[i].kva = bfa_mem_dma_virt(reqq_dma); - iocfc->req_cq_ba[i].pa = bfa_mem_dma_phys(reqq_dma); - memset(iocfc->req_cq_ba[i].kva, 0, per_reqq_sz); - - rspq_dma = BFA_MEM_RSPQ_DMA(bfa, i); - iocfc->rsp_cq_ba[i].kva = bfa_mem_dma_virt(rspq_dma); - iocfc->rsp_cq_ba[i].pa = bfa_mem_dma_phys(rspq_dma); - memset(iocfc->rsp_cq_ba[i].kva, 0, per_rspq_sz); + iocfc->req_cq_ba[i].kva = dm_kva; + iocfc->req_cq_ba[i].pa = dm_pa; + memset(dm_kva, 0, per_reqq_sz); + dm_kva += per_reqq_sz; + dm_pa += per_reqq_sz; + + iocfc->rsp_cq_ba[i].kva = dm_kva; + iocfc->rsp_cq_ba[i].pa = dm_pa; + memset(dm_kva, 0, per_rspq_sz); + dm_kva += per_rspq_sz; + dm_pa += per_rspq_sz; } - /* Claim IOCFC dma memory - for shadow CI/PI */ - dm_kva = bfa_mem_dma_virt(iocfc_dma); - dm_pa = bfa_mem_dma_phys(iocfc_dma); - for (i = 0; i < cfg->fwcfg.num_cqs; i++) { iocfc->req_cq_shadow_ci[i].kva = dm_kva; iocfc->req_cq_shadow_ci[i].pa = dm_pa; @@ -651,27 +572,36 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg) dm_pa += BFA_CACHELINE_SZ; } - /* Claim IOCFC dma memory - for the config info page */ + /* + * Claim DMA-able memory for the config info page + */ bfa->iocfc.cfg_info.kva = dm_kva; bfa->iocfc.cfg_info.pa = dm_pa; bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva; dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); - /* Claim IOCFC dma memory - for the config response */ + /* + * Claim DMA-able memory for the config response + */ bfa->iocfc.cfgrsp_dma.kva = dm_kva; bfa->iocfc.cfgrsp_dma.pa = dm_pa; bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva; - dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); + + dm_kva += + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), + BFA_CACHELINE_SZ); dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); + BFA_CACHELINE_SZ); + + + bfa_meminfo_dma_virt(meminfo) = dm_kva; + bfa_meminfo_dma_phys(meminfo) = dm_pa; - /* Claim IOCFC kva memory */ dbgsz = (bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0; if (dbgsz > 0) { - bfa_ioc_debug_memclaim(&bfa->ioc, bfa_mem_kva_curp(iocfc)); - bfa_mem_kva_curp(iocfc) += dbgsz; + bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo)); + bfa_meminfo_kva(meminfo) += dbgsz; } } @@ -683,9 +613,7 @@ bfa_iocfc_start_submod(struct bfa_s *bfa) { int i; - bfa->queue_process = BFA_TRUE; - for (i = 0; i < BFI_IOC_MAX_CQS; i++) - bfa_isr_rspq_ack(bfa, i); + bfa->rme_process = BFA_TRUE; for (i = 0; hal_mods[i]; i++) hal_mods[i]->start(bfa); @@ -731,16 +659,6 @@ bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl) bfa->iocfc.action = BFA_IOCFC_ACT_NONE; } -static void -bfa_iocfc_enable_cb(void *bfa_arg, bfa_boolean_t compl) -{ - struct bfa_s *bfa = bfa_arg; - struct bfad_s *bfad = bfa->bfad; - - if (compl) - complete(&bfad->enable_comp); -} - static void bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl) { @@ -751,37 +669,6 @@ bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl) complete(&bfad->disable_comp); } -/** - * configure queue registers from firmware response - */ -static void -bfa_iocfc_qreg(struct bfa_s *bfa, struct bfi_iocfc_qreg_s *qreg) -{ - int i; - struct bfa_iocfc_regs_s *r = &bfa->iocfc.bfa_regs; - void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - - for (i = 0; i < BFI_IOC_MAX_CQS; i++) { - bfa->iocfc.hw_qid[i] = qreg->hw_qid[i]; - r->cpe_q_ci[i] = kva + be32_to_cpu(qreg->cpe_q_ci_off[i]); - r->cpe_q_pi[i] = kva + be32_to_cpu(qreg->cpe_q_pi_off[i]); - r->cpe_q_ctrl[i] = kva + be32_to_cpu(qreg->cpe_qctl_off[i]); - r->rme_q_ci[i] = kva + be32_to_cpu(qreg->rme_q_ci_off[i]); - r->rme_q_pi[i] = kva + be32_to_cpu(qreg->rme_q_pi_off[i]); - r->rme_q_ctrl[i] = kva + be32_to_cpu(qreg->rme_qctl_off[i]); - } -} - -static void -bfa_iocfc_res_recfg(struct bfa_s *bfa, struct bfa_iocfc_fwcfg_s *fwcfg) -{ - bfa_fcxp_res_recfg(bfa, fwcfg->num_fcxp_reqs); - bfa_uf_res_recfg(bfa, fwcfg->num_uf_bufs); - bfa_rport_res_recfg(bfa, fwcfg->num_rports); - bfa_fcp_res_recfg(bfa, fwcfg->num_ioim_reqs); - bfa_tskim_res_recfg(bfa, fwcfg->num_tskim_reqs); -} - /* * Update BFA configuration from firmware configuration. */ @@ -794,7 +681,6 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa) fwcfg->num_cqs = fwcfg->num_cqs; fwcfg->num_ioim_reqs = be16_to_cpu(fwcfg->num_ioim_reqs); - fwcfg->num_fwtio_reqs = be16_to_cpu(fwcfg->num_fwtio_reqs); fwcfg->num_tskim_reqs = be16_to_cpu(fwcfg->num_tskim_reqs); fwcfg->num_fcxp_reqs = be16_to_cpu(fwcfg->num_fcxp_reqs); fwcfg->num_uf_bufs = be16_to_cpu(fwcfg->num_uf_bufs); @@ -802,21 +688,6 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa) iocfc->cfgdone = BFA_TRUE; - /* - * configure queue register offsets as learnt from firmware - */ - bfa_iocfc_qreg(bfa, &cfgrsp->qreg); - - /* - * Re-configure resources as learnt from Firmware - */ - bfa_iocfc_res_recfg(bfa, fwcfg); - - /* - * Install MSIX queue handlers - */ - bfa_msix_queue_install(bfa); - /* * Configuration is complete - initialize/start submodules */ @@ -824,12 +695,8 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa) if (iocfc->action == BFA_IOCFC_ACT_INIT) bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa); - else { - if (bfa->iocfc.action == BFA_IOCFC_ACT_ENABLE) - bfa_cb_queue(bfa, &bfa->iocfc.en_hcb_qe, - bfa_iocfc_enable_cb, bfa); + else bfa_iocfc_start_submod(bfa); - } } void bfa_iocfc_reset_queues(struct bfa_s *bfa) @@ -844,181 +711,6 @@ bfa_iocfc_reset_queues(struct bfa_s *bfa) } } -/* Fabric Assigned Address specific functions */ - -/* - * Check whether IOC is ready before sending command down - */ -static bfa_status_t -bfa_faa_validate_request(struct bfa_s *bfa) -{ - enum bfa_ioc_type_e ioc_type = bfa_get_type(bfa); - u32 card_type = bfa->ioc.attr->card_type; - - if (bfa_ioc_is_operational(&bfa->ioc)) { - if ((ioc_type != BFA_IOC_TYPE_FC) || bfa_mfg_is_mezz(card_type)) - return BFA_STATUS_FEATURE_NOT_SUPPORTED; - } else { - if (!bfa_ioc_is_acq_addr(&bfa->ioc)) - return BFA_STATUS_IOC_NON_OP; - } - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_faa_enable(struct bfa_s *bfa, bfa_cb_iocfc_t cbfn, void *cbarg) -{ - struct bfi_faa_en_dis_s faa_enable_req; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - bfa_status_t status; - - iocfc->faa_args.faa_cb.faa_cbfn = cbfn; - iocfc->faa_args.faa_cb.faa_cbarg = cbarg; - - status = bfa_faa_validate_request(bfa); - if (status != BFA_STATUS_OK) - return status; - - if (iocfc->faa_args.busy == BFA_TRUE) - return BFA_STATUS_DEVBUSY; - - if (iocfc->faa_args.faa_state == BFA_FAA_ENABLED) - return BFA_STATUS_FAA_ENABLED; - - if (bfa_fcport_is_trunk_enabled(bfa)) - return BFA_STATUS_ERROR_TRUNK_ENABLED; - - bfa_fcport_cfg_faa(bfa, BFA_FAA_ENABLED); - iocfc->faa_args.busy = BFA_TRUE; - - memset(&faa_enable_req, 0, sizeof(struct bfi_faa_en_dis_s)); - bfi_h2i_set(faa_enable_req.mh, BFI_MC_IOCFC, - BFI_IOCFC_H2I_FAA_ENABLE_REQ, bfa_fn_lpu(bfa)); - - bfa_ioc_mbox_send(&bfa->ioc, &faa_enable_req, - sizeof(struct bfi_faa_en_dis_s)); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_faa_disable(struct bfa_s *bfa, bfa_cb_iocfc_t cbfn, - void *cbarg) -{ - struct bfi_faa_en_dis_s faa_disable_req; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - bfa_status_t status; - - iocfc->faa_args.faa_cb.faa_cbfn = cbfn; - iocfc->faa_args.faa_cb.faa_cbarg = cbarg; - - status = bfa_faa_validate_request(bfa); - if (status != BFA_STATUS_OK) - return status; - - if (iocfc->faa_args.busy == BFA_TRUE) - return BFA_STATUS_DEVBUSY; - - if (iocfc->faa_args.faa_state == BFA_FAA_DISABLED) - return BFA_STATUS_FAA_DISABLED; - - bfa_fcport_cfg_faa(bfa, BFA_FAA_DISABLED); - iocfc->faa_args.busy = BFA_TRUE; - - memset(&faa_disable_req, 0, sizeof(struct bfi_faa_en_dis_s)); - bfi_h2i_set(faa_disable_req.mh, BFI_MC_IOCFC, - BFI_IOCFC_H2I_FAA_DISABLE_REQ, bfa_fn_lpu(bfa)); - - bfa_ioc_mbox_send(&bfa->ioc, &faa_disable_req, - sizeof(struct bfi_faa_en_dis_s)); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_faa_query(struct bfa_s *bfa, struct bfa_faa_attr_s *attr, - bfa_cb_iocfc_t cbfn, void *cbarg) -{ - struct bfi_faa_query_s faa_attr_req; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - bfa_status_t status; - - iocfc->faa_args.faa_attr = attr; - iocfc->faa_args.faa_cb.faa_cbfn = cbfn; - iocfc->faa_args.faa_cb.faa_cbarg = cbarg; - - status = bfa_faa_validate_request(bfa); - if (status != BFA_STATUS_OK) - return status; - - if (iocfc->faa_args.busy == BFA_TRUE) - return BFA_STATUS_DEVBUSY; - - iocfc->faa_args.busy = BFA_TRUE; - memset(&faa_attr_req, 0, sizeof(struct bfi_faa_query_s)); - bfi_h2i_set(faa_attr_req.mh, BFI_MC_IOCFC, - BFI_IOCFC_H2I_FAA_QUERY_REQ, bfa_fn_lpu(bfa)); - - bfa_ioc_mbox_send(&bfa->ioc, &faa_attr_req, - sizeof(struct bfi_faa_query_s)); - - return BFA_STATUS_OK; -} - -/* - * FAA enable response - */ -static void -bfa_faa_enable_reply(struct bfa_iocfc_s *iocfc, - struct bfi_faa_en_dis_rsp_s *rsp) -{ - void *cbarg = iocfc->faa_args.faa_cb.faa_cbarg; - bfa_status_t status = rsp->status; - - WARN_ON(!iocfc->faa_args.faa_cb.faa_cbfn); - - iocfc->faa_args.faa_cb.faa_cbfn(cbarg, status); - iocfc->faa_args.busy = BFA_FALSE; -} - -/* - * FAA disable response - */ -static void -bfa_faa_disable_reply(struct bfa_iocfc_s *iocfc, - struct bfi_faa_en_dis_rsp_s *rsp) -{ - void *cbarg = iocfc->faa_args.faa_cb.faa_cbarg; - bfa_status_t status = rsp->status; - - WARN_ON(!iocfc->faa_args.faa_cb.faa_cbfn); - - iocfc->faa_args.faa_cb.faa_cbfn(cbarg, status); - iocfc->faa_args.busy = BFA_FALSE; -} - -/* - * FAA query response - */ -static void -bfa_faa_query_reply(struct bfa_iocfc_s *iocfc, - bfi_faa_query_rsp_t *rsp) -{ - void *cbarg = iocfc->faa_args.faa_cb.faa_cbarg; - - if (iocfc->faa_args.faa_attr) { - iocfc->faa_args.faa_attr->faa = rsp->faa; - iocfc->faa_args.faa_attr->faa_state = rsp->faa_status; - iocfc->faa_args.faa_attr->pwwn_source = rsp->addr_source; - } - - WARN_ON(!iocfc->faa_args.faa_cb.faa_cbfn); - - iocfc->faa_args.faa_cb.faa_cbfn(cbarg, BFA_STATUS_OK); - iocfc->faa_args.busy = BFA_FALSE; -} - /* * IOC enable request is complete */ @@ -1027,20 +719,11 @@ bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status) { struct bfa_s *bfa = bfa_arg; - if (status == BFA_STATUS_FAA_ACQ_ADDR) { - bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, - bfa_iocfc_init_cb, bfa); - return; - } - if (status != BFA_STATUS_OK) { bfa_isr_disable(bfa); if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb, bfa); - else if (bfa->iocfc.action == BFA_IOCFC_ACT_ENABLE) - bfa_cb_queue(bfa, &bfa->iocfc.en_hcb_qe, - bfa_iocfc_enable_cb, bfa); return; } @@ -1076,7 +759,7 @@ bfa_iocfc_hbfail_cbfn(void *bfa_arg) { struct bfa_s *bfa = bfa_arg; - bfa->queue_process = BFA_FALSE; + bfa->rme_process = BFA_FALSE; bfa_isr_disable(bfa); bfa_iocfc_disable_submod(bfa); @@ -1103,47 +786,15 @@ bfa_iocfc_reset_cbfn(void *bfa_arg) * Query IOC memory requirement information. */ void -bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) +bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) { - int q, per_reqq_sz, per_rspq_sz; - struct bfa_mem_dma_s *ioc_dma = BFA_MEM_IOC_DMA(bfa); - struct bfa_mem_dma_s *iocfc_dma = BFA_MEM_IOCFC_DMA(bfa); - struct bfa_mem_kva_s *iocfc_kva = BFA_MEM_IOCFC_KVA(bfa); - u32 dm_len = 0; - - /* dma memory setup for IOC */ - bfa_mem_dma_setup(meminfo, ioc_dma, - BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ)); - - /* dma memory setup for REQ/RSP queues */ - per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - - for (q = 0; q < cfg->fwcfg.num_cqs; q++) { - bfa_mem_dma_setup(meminfo, BFA_MEM_REQQ_DMA(bfa, q), - per_reqq_sz); - bfa_mem_dma_setup(meminfo, BFA_MEM_RSPQ_DMA(bfa, q), - per_rspq_sz); - } - - /* IOCFC dma memory - calculate Shadow CI/PI size */ - for (q = 0; q < cfg->fwcfg.num_cqs; q++) - dm_len += (2 * BFA_CACHELINE_SZ); - - /* IOCFC dma memory - calculate config info / rsp size */ - dm_len += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); - dm_len += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); + /* dma memory for IOC */ + *dm_len += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ); - /* dma memory setup for IOCFC */ - bfa_mem_dma_setup(meminfo, iocfc_dma, dm_len); - - /* kva memory setup for IOCFC */ - bfa_mem_kva_setup(meminfo, iocfc_kva, - ((bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0)); + bfa_iocfc_fw_cfg_sz(cfg, dm_len); + bfa_iocfc_cqs_sz(cfg, dm_len); + *km_len += (bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0; } /* @@ -1151,7 +802,7 @@ bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, */ void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { int i; struct bfa_ioc_s *ioc = &bfa->ioc; @@ -1164,11 +815,17 @@ bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, ioc->trcmod = bfa->trcmod; bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod); - bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_PCIFN_CLASS_FC); + /* + * Set FC mode for BFA_PCI_DEVICE_ID_CT_FC. + */ + if (pcidev->device_id == BFA_PCI_DEVICE_ID_CT_FC) + bfa_ioc_set_fcmode(&bfa->ioc); + + bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC); bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs); bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev); - bfa_iocfc_mem_claim(bfa, cfg); + bfa_iocfc_mem_claim(bfa, cfg, meminfo); INIT_LIST_HEAD(&bfa->timer_mod.timer_q); INIT_LIST_HEAD(&bfa->comp_q); @@ -1206,7 +863,7 @@ bfa_iocfc_stop(struct bfa_s *bfa) { bfa->iocfc.action = BFA_IOCFC_ACT_STOP; - bfa->queue_process = BFA_FALSE; + bfa->rme_process = BFA_FALSE; bfa_ioc_disable(&bfa->ioc); } @@ -1222,22 +879,12 @@ bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m) switch (msg->mh.msg_id) { case BFI_IOCFC_I2H_CFG_REPLY: + iocfc->cfg_reply = &msg->cfg_reply; bfa_iocfc_cfgrsp(bfa); break; case BFI_IOCFC_I2H_UPDATEQ_RSP: iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK); break; - case BFI_IOCFC_I2H_FAA_ENABLE_RSP: - bfa_faa_enable_reply(iocfc, - (struct bfi_faa_en_dis_rsp_s *)msg); - break; - case BFI_IOCFC_I2H_FAA_DISABLE_RSP: - bfa_faa_disable_reply(iocfc, - (struct bfi_faa_en_dis_rsp_s *)msg); - break; - case BFI_IOCFC_I2H_FAA_QUERY_RSP: - bfa_faa_query_reply(iocfc, (bfi_faa_query_rsp_t *)msg); - break; default: WARN_ON(1); } @@ -1279,7 +926,7 @@ bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) return BFA_STATUS_DEVBUSY; bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ, - bfa_fn_lpu(bfa)); + bfa_lpuid(bfa)); m->coalesce = iocfc->cfginfo->intr_attr.coalesce; m->delay = iocfc->cfginfo->intr_attr.delay; m->latency = iocfc->cfginfo->intr_attr.latency; @@ -1287,17 +934,17 @@ bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) bfa_trc(bfa, attr->delay); bfa_trc(bfa, attr->latency); - bfa_reqq_produce(bfa, BFA_REQQ_IOC, m->mh); + bfa_reqq_produce(bfa, BFA_REQQ_IOC); return BFA_STATUS_OK; } void -bfa_iocfc_set_snsbase(struct bfa_s *bfa, int seg_no, u64 snsbase_pa) +bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa) { struct bfa_iocfc_s *iocfc = &bfa->iocfc; iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1); - bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase[seg_no], snsbase_pa); + bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa); } /* * Enable IOC after it is disabled. @@ -1307,7 +954,6 @@ bfa_iocfc_enable(struct bfa_s *bfa) { bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, "IOC Enable"); - bfa->iocfc.action = BFA_IOCFC_ACT_ENABLE; bfa_ioc_enable(&bfa->ioc); } @@ -1318,7 +964,7 @@ bfa_iocfc_disable(struct bfa_s *bfa) "IOC Disable"); bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE; - bfa->queue_process = BFA_FALSE; + bfa->rme_process = BFA_FALSE; bfa_ioc_disable(&bfa->ioc); } @@ -1387,49 +1033,33 @@ bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, struct bfi_pbc_vport_s *pbc_vport) * starting address for each block and provide the same * structure as input parameter to bfa_attach() call. * - * @param[in] bfa - pointer to the bfa structure, used while fetching the - * dma, kva memory information of the bfa sub-modules. - * * @return void * * Special Considerations: @note */ void -bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) +bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo) { int i; - struct bfa_mem_dma_s *port_dma = BFA_MEM_PORT_DMA(bfa); - struct bfa_mem_dma_s *ablk_dma = BFA_MEM_ABLK_DMA(bfa); - struct bfa_mem_dma_s *cee_dma = BFA_MEM_CEE_DMA(bfa); - struct bfa_mem_dma_s *sfp_dma = BFA_MEM_SFP_DMA(bfa); - struct bfa_mem_dma_s *flash_dma = BFA_MEM_FLASH_DMA(bfa); - struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa); - struct bfa_mem_dma_s *phy_dma = BFA_MEM_PHY_DMA(bfa); + u32 km_len = 0, dm_len = 0; WARN_ON((cfg == NULL) || (meminfo == NULL)); memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s)); + meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_type = + BFA_MEM_TYPE_KVA; + meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_type = + BFA_MEM_TYPE_DMA; - /* Initialize the DMA & KVA meminfo queues */ - INIT_LIST_HEAD(&meminfo->dma_info.qe); - INIT_LIST_HEAD(&meminfo->kva_info.qe); - - bfa_iocfc_meminfo(cfg, meminfo, bfa); + bfa_iocfc_meminfo(cfg, &km_len, &dm_len); for (i = 0; hal_mods[i]; i++) - hal_mods[i]->meminfo(cfg, meminfo, bfa); - - /* dma info setup */ - bfa_mem_dma_setup(meminfo, port_dma, bfa_port_meminfo()); - bfa_mem_dma_setup(meminfo, ablk_dma, bfa_ablk_meminfo()); - bfa_mem_dma_setup(meminfo, cee_dma, bfa_cee_meminfo()); - bfa_mem_dma_setup(meminfo, sfp_dma, bfa_sfp_meminfo()); - bfa_mem_dma_setup(meminfo, flash_dma, - bfa_flash_meminfo(cfg->drvcfg.min_cfg)); - bfa_mem_dma_setup(meminfo, diag_dma, bfa_diag_meminfo()); - bfa_mem_dma_setup(meminfo, phy_dma, - bfa_phy_meminfo(cfg->drvcfg.min_cfg)); + hal_mods[i]->meminfo(cfg, &km_len, &dm_len); + + dm_len += bfa_port_meminfo(); + + meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_len = km_len; + meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len; } /* @@ -1462,46 +1092,28 @@ void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { - int i; - struct bfa_mem_dma_s *dma_info, *dma_elem; - struct bfa_mem_kva_s *kva_info, *kva_elem; - struct list_head *dm_qe, *km_qe; + int i; + struct bfa_mem_elem_s *melem; bfa->fcs = BFA_FALSE; WARN_ON((cfg == NULL) || (meminfo == NULL)); - /* Initialize memory pointers for iterative allocation */ - dma_info = &meminfo->dma_info; - dma_info->kva_curp = dma_info->kva; - dma_info->dma_curp = dma_info->dma; - - kva_info = &meminfo->kva_info; - kva_info->kva_curp = kva_info->kva; - - list_for_each(dm_qe, &dma_info->qe) { - dma_elem = (struct bfa_mem_dma_s *) dm_qe; - dma_elem->kva_curp = dma_elem->kva; - dma_elem->dma_curp = dma_elem->dma; - } - - list_for_each(km_qe, &kva_info->qe) { - kva_elem = (struct bfa_mem_kva_s *) km_qe; - kva_elem->kva_curp = kva_elem->kva; + /* + * initialize all memory pointers for iterative allocation + */ + for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { + melem = meminfo->meminfo + i; + melem->kva_curp = melem->kva; + melem->dma_curp = melem->dma; } - bfa_iocfc_attach(bfa, bfad, cfg, pcidev); + bfa_iocfc_attach(bfa, bfad, cfg, meminfo, pcidev); for (i = 0; hal_mods[i]; i++) - hal_mods[i]->attach(bfa, bfad, cfg, pcidev); - - bfa_com_port_attach(bfa); - bfa_com_ablk_attach(bfa); - bfa_com_cee_attach(bfa); - bfa_com_sfp_attach(bfa); - bfa_com_flash_attach(bfa, cfg->drvcfg.min_cfg); - bfa_com_diag_attach(bfa); - bfa_com_phy_attach(bfa, cfg->drvcfg.min_cfg); + hal_mods[i]->attach(bfa, bfad, cfg, meminfo, pcidev); + + bfa_com_port_attach(bfa, meminfo); } /* @@ -1603,7 +1215,6 @@ bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg) cfg->fwcfg.num_fcxp_reqs = DEF_CFG_NUM_FCXP_REQS; cfg->fwcfg.num_uf_bufs = DEF_CFG_NUM_UF_BUFS; cfg->fwcfg.num_cqs = DEF_CFG_NUM_CQS; - cfg->fwcfg.num_fwtio_reqs = 0; cfg->drvcfg.num_reqq_elems = DEF_CFG_NUM_REQQ_ELEMS; cfg->drvcfg.num_rspq_elems = DEF_CFG_NUM_RSPQ_ELEMS; @@ -1625,7 +1236,6 @@ bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg) cfg->fwcfg.num_fcxp_reqs = BFA_FCXP_MIN; cfg->fwcfg.num_uf_bufs = BFA_UF_MIN; cfg->fwcfg.num_rports = BFA_RPORT_MIN; - cfg->fwcfg.num_fwtio_reqs = 0; cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; cfg->drvcfg.num_reqq_elems = BFA_REQQ_NELEMS_MIN; diff --git a/trunk/drivers/scsi/bfa/bfa_defs.h b/trunk/drivers/scsi/bfa/bfa_defs.h index ed8d31b0188b..d85f93aea465 100644 --- a/trunk/drivers/scsi/bfa/bfa_defs.h +++ b/trunk/drivers/scsi/bfa/bfa_defs.h @@ -40,12 +40,7 @@ enum { BFA_MFG_TYPE_ASTRA = 807, /* Astra mezz card */ BFA_MFG_TYPE_LIGHTNING_P0 = 902, /* Lightning mezz card - old */ BFA_MFG_TYPE_LIGHTNING = 1741, /* Lightning mezz card */ - BFA_MFG_TYPE_PROWLER_F = 1560, /* Prowler FC only cards */ - BFA_MFG_TYPE_PROWLER_N = 1410, /* Prowler NIC only cards */ - BFA_MFG_TYPE_PROWLER_C = 1710, /* Prowler CNA only cards */ - BFA_MFG_TYPE_PROWLER_D = 1860, /* Prowler Dual cards */ - BFA_MFG_TYPE_CHINOOK = 1867, /* Chinook cards */ - BFA_MFG_TYPE_INVALID = 0, /* Invalid card type */ + BFA_MFG_TYPE_INVALID = 0, /* Invalid card type */ }; #pragma pack(1) @@ -58,8 +53,7 @@ enum { (type) == BFA_MFG_TYPE_WANCHESE || \ (type) == BFA_MFG_TYPE_ASTRA || \ (type) == BFA_MFG_TYPE_LIGHTNING_P0 || \ - (type) == BFA_MFG_TYPE_LIGHTNING || \ - (type) == BFA_MFG_TYPE_CHINOOK)) + (type) == BFA_MFG_TYPE_LIGHTNING)) /* * Check if the card having old wwn/mac handling @@ -130,53 +124,30 @@ enum bfa_status { BFA_STATUS_ETIMER = 5, /* Timer expired - Retry, if persists, * contact support */ BFA_STATUS_EPROTOCOL = 6, /* Protocol error */ - BFA_STATUS_SFP_UNSUPP = 10, /* Unsupported SFP - Replace SFP */ - BFA_STATUS_UNKNOWN_VFID = 11, /* VF_ID not found */ - BFA_STATUS_DATACORRUPTED = 12, /* Diag returned data corrupted */ BFA_STATUS_DEVBUSY = 13, /* Device busy - Retry operation */ - BFA_STATUS_HDMA_FAILED = 16, /* Host dma failed contact support */ - BFA_STATUS_FLASH_BAD_LEN = 17, /* Flash bad length */ BFA_STATUS_UNKNOWN_LWWN = 18, /* LPORT PWWN not found */ BFA_STATUS_UNKNOWN_RWWN = 19, /* RPORT PWWN not found */ BFA_STATUS_VPORT_EXISTS = 21, /* VPORT already exists */ BFA_STATUS_VPORT_MAX = 22, /* Reached max VPORT supported limit */ BFA_STATUS_UNSUPP_SPEED = 23, /* Invalid Speed Check speed setting */ BFA_STATUS_INVLD_DFSZ = 24, /* Invalid Max data field size */ - BFA_STATUS_CMD_NOTSUPP = 26, /* Command/API not supported */ BFA_STATUS_FABRIC_RJT = 29, /* Reject from attached fabric */ - BFA_STATUS_PORT_OFFLINE = 34, /* Port is not online */ BFA_STATUS_VPORT_WWN_BP = 46, /* WWN is same as base port's WWN */ - BFA_STATUS_PORT_NOT_DISABLED = 47, /* Port not disabled disable port */ BFA_STATUS_NO_FCPIM_NEXUS = 52, /* No FCP Nexus exists with the rport */ BFA_STATUS_IOC_FAILURE = 56, /* IOC failure - Retry, if persists * contact support */ BFA_STATUS_INVALID_WWN = 57, /* Invalid WWN */ - BFA_STATUS_ADAPTER_ENABLED = 60, /* Adapter is not disabled */ - BFA_STATUS_IOC_NON_OP = 61, /* IOC is not operational */ - BFA_STATUS_VERSION_FAIL = 70, /* Application/Driver version mismatch */ BFA_STATUS_DIAG_BUSY = 71, /* diag busy */ - BFA_STATUS_BEACON_ON = 72, /* Port Beacon already on */ BFA_STATUS_ENOFSAVE = 78, /* No saved firmware trace */ BFA_STATUS_IOC_DISABLED = 82, /* IOC is already disabled */ - BFA_STATUS_NO_SFP_DEV = 89, /* No SFP device check or replace SFP */ - BFA_STATUS_MEMTEST_FAILED = 90, /* Memory test failed contact support */ - BFA_STATUS_LEDTEST_OP = 109, /* LED test is operating */ BFA_STATUS_INVALID_MAC = 134, /* Invalid MAC address */ BFA_STATUS_PBC = 154, /* Operation not allowed for pre-boot * configuration */ - BFA_STATUS_SFP_NOT_READY = 159, /* SFP info is not ready. Retry */ BFA_STATUS_TRUNK_ENABLED = 164, /* Trunk is already enabled on * this adapter */ BFA_STATUS_TRUNK_DISABLED = 165, /* Trunking is disabled on * the adapter */ BFA_STATUS_IOPROFILE_OFF = 175, /* IO profile OFF */ - BFA_STATUS_PHY_NOT_PRESENT = 183, /* PHY module not present */ - BFA_STATUS_FEATURE_NOT_SUPPORTED = 192, /* Feature not supported */ - BFA_STATUS_FAA_ENABLED = 197, /* FAA is already enabled */ - BFA_STATUS_FAA_DISABLED = 198, /* FAA is already disabled */ - BFA_STATUS_FAA_ACQUIRED = 199, /* FAA is already acquired */ - BFA_STATUS_FAA_ACQ_ADDR = 200, /* Acquiring addr */ - BFA_STATUS_ERROR_TRUNK_ENABLED = 203, /* Trunk enabled on adapter */ BFA_STATUS_MAX_VAL /* Unknown error code */ }; #define bfa_status_t enum bfa_status @@ -294,8 +265,6 @@ enum bfa_ioc_state { BFA_IOC_DISABLED = 10, /* IOC is disabled */ BFA_IOC_FWMISMATCH = 11, /* IOC f/w different from drivers */ BFA_IOC_ENABLING = 12, /* IOC is being enabled */ - BFA_IOC_HWFAIL = 13, /* PCI mapping doesn't exist */ - BFA_IOC_ACQ_ADDR = 14, /* Acquiring addr from fabric */ }; /* @@ -325,7 +294,6 @@ struct bfa_ioc_drv_stats_s { u32 enable_reqs; u32 disable_replies; u32 enable_replies; - u32 rsvd; }; /* @@ -352,10 +320,7 @@ struct bfa_ioc_attr_s { struct bfa_ioc_driver_attr_s driver_attr; /* driver attr */ struct bfa_ioc_pci_attr_s pci_attr; u8 port_id; /* port number */ - u8 port_mode; /* bfa_mode_s */ - u8 cap_bm; /* capability */ - u8 port_mode_cfg; /* bfa_mode_s */ - u8 rsvd[4]; /* 64bit align */ + u8 rsvd[7]; /* 64bit align */ }; /* @@ -372,21 +337,6 @@ struct bfa_ioc_attr_s { #define BFA_MFG_SUPPLIER_PARTNUM_SIZE 20 #define BFA_MFG_SUPPLIER_SERIALNUM_SIZE 20 #define BFA_MFG_SUPPLIER_REVISION_SIZE 4 -/* - * Initial capability definition - */ -#define BFA_MFG_IC_FC 0x01 -#define BFA_MFG_IC_ETH 0x02 - -/* - * Adapter capability mask definition - */ -#define BFA_CM_HBA 0x01 -#define BFA_CM_CNA 0x02 -#define BFA_CM_NIC 0x04 -#define BFA_CM_FC16G 0x08 -#define BFA_CM_SRIOV 0x10 -#define BFA_CM_MEZZ 0x20 #pragma pack(1) @@ -394,39 +344,31 @@ struct bfa_ioc_attr_s { * All numerical fields are in big-endian format. */ struct bfa_mfg_block_s { - u8 version; /*!< manufacturing block version */ - u8 mfg_sig[3]; /*!< characters 'M', 'F', 'G' */ - u16 mfgsize; /*!< mfg block size */ - u16 u16_chksum; /*!< old u16 checksum */ - char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)]; - char brcd_partnum[STRSZ(BFA_MFG_PARTNUM_SIZE)]; - u8 mfg_day; /*!< manufacturing day */ - u8 mfg_month; /*!< manufacturing month */ - u16 mfg_year; /*!< manufacturing year */ - wwn_t mfg_wwn; /*!< wwn base for this adapter */ - u8 num_wwn; /*!< number of wwns assigned */ - u8 mfg_speeds; /*!< speeds allowed for this adapter */ - u8 rsv[2]; - char supplier_id[STRSZ(BFA_MFG_SUPPLIER_ID_SIZE)]; - char supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)]; - char supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)]; - char supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)]; - mac_t mfg_mac; /*!< base mac address */ - u8 num_mac; /*!< number of mac addresses */ - u8 rsv2; - u32 card_type; /*!< card type */ - char cap_nic; /*!< capability nic */ - char cap_cna; /*!< capability cna */ - char cap_hba; /*!< capability hba */ - char cap_fc16g; /*!< capability fc 16g */ - char cap_sriov; /*!< capability sriov */ - char cap_mezz; /*!< capability mezz */ - u8 rsv3; - u8 mfg_nports; /*!< number of ports */ - char media[8]; /*!< xfi/xaui */ - char initial_mode[8]; /*!< initial mode: hba/cna/nic */ - u8 rsv4[84]; - u8 md5_chksum[BFA_MFG_CHKSUM_SIZE]; /*!< md5 checksum */ + u8 version; /* manufacturing block version */ + u8 mfg_sig[3]; /* characters 'M', 'F', 'G' */ + u16 mfgsize; /* mfg block size */ + u16 u16_chksum; /* old u16 checksum */ + char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)]; + char brcd_partnum[STRSZ(BFA_MFG_PARTNUM_SIZE)]; + u8 mfg_day; /* manufacturing day */ + u8 mfg_month; /* manufacturing month */ + u16 mfg_year; /* manufacturing year */ + wwn_t mfg_wwn; /* wwn base for this adapter */ + u8 num_wwn; /* number of wwns assigned */ + u8 mfg_speeds; /* speeds allowed for this adapter */ + u8 rsv[2]; + char supplier_id[STRSZ(BFA_MFG_SUPPLIER_ID_SIZE)]; + char supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)]; + char + supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)]; + char + supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)]; + mac_t mfg_mac; /* mac address */ + u8 num_mac; /* number of mac addresses */ + u8 rsv2; + u32 mfg_type; /* card type */ + u8 rsv3[108]; + u8 md5_chksum[BFA_MFG_CHKSUM_SIZE]; /* md5 checksum */ }; #pragma pack() @@ -444,27 +386,17 @@ enum { BFA_PCI_DEVICE_ID_FC_8G1P = 0x17, BFA_PCI_DEVICE_ID_CT = 0x14, BFA_PCI_DEVICE_ID_CT_FC = 0x21, - BFA_PCI_DEVICE_ID_CT2 = 0x22, }; -#define bfa_asic_id_cb(__d) \ - ((__d) == BFA_PCI_DEVICE_ID_FC_8G2P || \ - (__d) == BFA_PCI_DEVICE_ID_FC_8G1P) -#define bfa_asic_id_ct(__d) \ - ((__d) == BFA_PCI_DEVICE_ID_CT || \ - (__d) == BFA_PCI_DEVICE_ID_CT_FC) -#define bfa_asic_id_ct2(__d) ((__d) == BFA_PCI_DEVICE_ID_CT2) -#define bfa_asic_id_ctc(__d) \ - (bfa_asic_id_ct(__d) || bfa_asic_id_ct2(__d)) +#define bfa_asic_id_ct(devid) \ + ((devid) == BFA_PCI_DEVICE_ID_CT || \ + (devid) == BFA_PCI_DEVICE_ID_CT_FC) /* * PCI sub-system device and vendor ID information */ enum { BFA_PCI_FCOE_SSDEVICE_ID = 0x14, - BFA_PCI_CT2_SSID_FCoE = 0x22, - BFA_PCI_CT2_SSID_ETH = 0x23, - BFA_PCI_CT2_SSID_FC = 0x24, }; /* @@ -484,7 +416,9 @@ enum bfa_port_speed { BFA_PORT_SPEED_8GBPS = 8, BFA_PORT_SPEED_10GBPS = 10, BFA_PORT_SPEED_16GBPS = 16, - BFA_PORT_SPEED_AUTO = 0xf, + BFA_PORT_SPEED_AUTO = + (BFA_PORT_SPEED_1GBPS | BFA_PORT_SPEED_2GBPS | + BFA_PORT_SPEED_4GBPS | BFA_PORT_SPEED_8GBPS), }; #define bfa_port_speed_t enum bfa_port_speed @@ -529,453 +463,4 @@ struct bfa_boot_pbc_s { struct bfa_boot_bootlun_s pblun[BFA_PREBOOT_BOOTLUN_MAX]; }; -/* - * ASIC block configuration related structures - */ -#define BFA_ABLK_MAX_PORTS 2 -#define BFA_ABLK_MAX_PFS 16 -#define BFA_ABLK_MAX 2 - -#pragma pack(1) -enum bfa_mode_s { - BFA_MODE_HBA = 1, - BFA_MODE_CNA = 2, - BFA_MODE_NIC = 3 -}; - -struct bfa_adapter_cfg_mode_s { - u16 max_pf; - u16 max_vf; - enum bfa_mode_s mode; -}; - -struct bfa_ablk_cfg_pf_s { - u16 pers; - u8 port_id; - u8 optrom; - u8 valid; - u8 sriov; - u8 max_vfs; - u8 rsvd[1]; - u16 num_qpairs; - u16 num_vectors; - u32 bw; -}; - -struct bfa_ablk_cfg_port_s { - u8 mode; - u8 type; - u8 max_pfs; - u8 rsvd[5]; -}; - -struct bfa_ablk_cfg_inst_s { - u8 nports; - u8 max_pfs; - u8 rsvd[6]; - struct bfa_ablk_cfg_pf_s pf_cfg[BFA_ABLK_MAX_PFS]; - struct bfa_ablk_cfg_port_s port_cfg[BFA_ABLK_MAX_PORTS]; -}; - -struct bfa_ablk_cfg_s { - struct bfa_ablk_cfg_inst_s inst[BFA_ABLK_MAX]; -}; - - -/* - * SFP module specific - */ -#define SFP_DIAGMON_SIZE 10 /* num bytes of diag monitor data */ - -enum bfa_defs_sfp_media_e { - BFA_SFP_MEDIA_UNKNOWN = 0x00, - BFA_SFP_MEDIA_CU = 0x01, - BFA_SFP_MEDIA_LW = 0x02, - BFA_SFP_MEDIA_SW = 0x03, - BFA_SFP_MEDIA_EL = 0x04, - BFA_SFP_MEDIA_UNSUPPORT = 0x05, -}; - -/* - * values for xmtr_tech above - */ -enum { - SFP_XMTR_TECH_CU = (1 << 0), /* copper FC-BaseT */ - SFP_XMTR_TECH_CP = (1 << 1), /* copper passive */ - SFP_XMTR_TECH_CA = (1 << 2), /* copper active */ - SFP_XMTR_TECH_LL = (1 << 3), /* longwave laser */ - SFP_XMTR_TECH_SL = (1 << 4), /* shortwave laser w/ OFC */ - SFP_XMTR_TECH_SN = (1 << 5), /* shortwave laser w/o OFC */ - SFP_XMTR_TECH_EL_INTRA = (1 << 6), /* elec intra-enclosure */ - SFP_XMTR_TECH_EL_INTER = (1 << 7), /* elec inter-enclosure */ - SFP_XMTR_TECH_LC = (1 << 8), /* longwave laser */ - SFP_XMTR_TECH_SA = (1 << 9) -}; - -/* - * Serial ID: Data Fields -- Address A0h - * Basic ID field total 64 bytes - */ -struct sfp_srlid_base_s { - u8 id; /* 00: Identifier */ - u8 extid; /* 01: Extended Identifier */ - u8 connector; /* 02: Connector */ - u8 xcvr[8]; /* 03-10: Transceiver */ - u8 encoding; /* 11: Encoding */ - u8 br_norm; /* 12: BR, Nominal */ - u8 rate_id; /* 13: Rate Identifier */ - u8 len_km; /* 14: Length single mode km */ - u8 len_100m; /* 15: Length single mode 100m */ - u8 len_om2; /* 16: Length om2 fiber 10m */ - u8 len_om1; /* 17: Length om1 fiber 10m */ - u8 len_cu; /* 18: Length copper 1m */ - u8 len_om3; /* 19: Length om3 fiber 10m */ - u8 vendor_name[16];/* 20-35 */ - u8 unalloc1; - u8 vendor_oui[3]; /* 37-39 */ - u8 vendor_pn[16]; /* 40-55 */ - u8 vendor_rev[4]; /* 56-59 */ - u8 wavelen[2]; /* 60-61 */ - u8 unalloc2; - u8 cc_base; /* 63: check code for base id field */ -}; - -/* - * Serial ID: Data Fields -- Address A0h - * Extended id field total 32 bytes - */ -struct sfp_srlid_ext_s { - u8 options[2]; - u8 br_max; - u8 br_min; - u8 vendor_sn[16]; - u8 date_code[8]; - u8 diag_mon_type; /* 92: Diagnostic Monitoring type */ - u8 en_options; - u8 sff_8472; - u8 cc_ext; -}; - -/* - * Diagnostic: Data Fields -- Address A2h - * Diagnostic and control/status base field total 96 bytes - */ -struct sfp_diag_base_s { - /* - * Alarm and warning Thresholds 40 bytes - */ - u8 temp_high_alarm[2]; /* 00-01 */ - u8 temp_low_alarm[2]; /* 02-03 */ - u8 temp_high_warning[2]; /* 04-05 */ - u8 temp_low_warning[2]; /* 06-07 */ - - u8 volt_high_alarm[2]; /* 08-09 */ - u8 volt_low_alarm[2]; /* 10-11 */ - u8 volt_high_warning[2]; /* 12-13 */ - u8 volt_low_warning[2]; /* 14-15 */ - - u8 bias_high_alarm[2]; /* 16-17 */ - u8 bias_low_alarm[2]; /* 18-19 */ - u8 bias_high_warning[2]; /* 20-21 */ - u8 bias_low_warning[2]; /* 22-23 */ - - u8 tx_pwr_high_alarm[2]; /* 24-25 */ - u8 tx_pwr_low_alarm[2]; /* 26-27 */ - u8 tx_pwr_high_warning[2]; /* 28-29 */ - u8 tx_pwr_low_warning[2]; /* 30-31 */ - - u8 rx_pwr_high_alarm[2]; /* 32-33 */ - u8 rx_pwr_low_alarm[2]; /* 34-35 */ - u8 rx_pwr_high_warning[2]; /* 36-37 */ - u8 rx_pwr_low_warning[2]; /* 38-39 */ - - u8 unallocate_1[16]; - - /* - * ext_cal_const[36] - */ - u8 rx_pwr[20]; - u8 tx_i[4]; - u8 tx_pwr[4]; - u8 temp[4]; - u8 volt[4]; - u8 unallocate_2[3]; - u8 cc_dmi; -}; - -/* - * Diagnostic: Data Fields -- Address A2h - * Diagnostic and control/status extended field total 24 bytes - */ -struct sfp_diag_ext_s { - u8 diag[SFP_DIAGMON_SIZE]; - u8 unalloc1[4]; - u8 status_ctl; - u8 rsvd; - u8 alarm_flags[2]; - u8 unalloc2[2]; - u8 warning_flags[2]; - u8 ext_status_ctl[2]; -}; - -struct sfp_mem_s { - struct sfp_srlid_base_s srlid_base; - struct sfp_srlid_ext_s srlid_ext; - struct sfp_diag_base_s diag_base; - struct sfp_diag_ext_s diag_ext; -}; - -/* - * transceiver codes (SFF-8472 Rev 10.2 Table 3.5) - */ -union sfp_xcvr_e10g_code_u { - u8 b; - struct { -#ifdef __BIGENDIAN - u8 e10g_unall:1; /* 10G Ethernet compliance */ - u8 e10g_lrm:1; - u8 e10g_lr:1; - u8 e10g_sr:1; - u8 ib_sx:1; /* Infiniband compliance */ - u8 ib_lx:1; - u8 ib_cu_a:1; - u8 ib_cu_p:1; -#else - u8 ib_cu_p:1; - u8 ib_cu_a:1; - u8 ib_lx:1; - u8 ib_sx:1; /* Infiniband compliance */ - u8 e10g_sr:1; - u8 e10g_lr:1; - u8 e10g_lrm:1; - u8 e10g_unall:1; /* 10G Ethernet compliance */ -#endif - } r; -}; - -union sfp_xcvr_so1_code_u { - u8 b; - struct { - u8 escon:2; /* ESCON compliance code */ - u8 oc192_reach:1; /* SONET compliance code */ - u8 so_reach:2; - u8 oc48_reach:3; - } r; -}; - -union sfp_xcvr_so2_code_u { - u8 b; - struct { - u8 reserved:1; - u8 oc12_reach:3; /* OC12 reach */ - u8 reserved1:1; - u8 oc3_reach:3; /* OC3 reach */ - } r; -}; - -union sfp_xcvr_eth_code_u { - u8 b; - struct { - u8 base_px:1; - u8 base_bx10:1; - u8 e100base_fx:1; - u8 e100base_lx:1; - u8 e1000base_t:1; - u8 e1000base_cx:1; - u8 e1000base_lx:1; - u8 e1000base_sx:1; - } r; -}; - -struct sfp_xcvr_fc1_code_s { - u8 link_len:5; /* FC link length */ - u8 xmtr_tech2:3; - u8 xmtr_tech1:7; /* FC transmitter technology */ - u8 reserved1:1; -}; - -union sfp_xcvr_fc2_code_u { - u8 b; - struct { - u8 tw_media:1; /* twin axial pair (tw) */ - u8 tp_media:1; /* shielded twisted pair (sp) */ - u8 mi_media:1; /* miniature coax (mi) */ - u8 tv_media:1; /* video coax (tv) */ - u8 m6_media:1; /* multimode, 62.5m (m6) */ - u8 m5_media:1; /* multimode, 50m (m5) */ - u8 reserved:1; - u8 sm_media:1; /* single mode (sm) */ - } r; -}; - -union sfp_xcvr_fc3_code_u { - u8 b; - struct { -#ifdef __BIGENDIAN - u8 rsv4:1; - u8 mb800:1; /* 800 Mbytes/sec */ - u8 mb1600:1; /* 1600 Mbytes/sec */ - u8 mb400:1; /* 400 Mbytes/sec */ - u8 rsv2:1; - u8 mb200:1; /* 200 Mbytes/sec */ - u8 rsv1:1; - u8 mb100:1; /* 100 Mbytes/sec */ -#else - u8 mb100:1; /* 100 Mbytes/sec */ - u8 rsv1:1; - u8 mb200:1; /* 200 Mbytes/sec */ - u8 rsv2:1; - u8 mb400:1; /* 400 Mbytes/sec */ - u8 mb1600:1; /* 1600 Mbytes/sec */ - u8 mb800:1; /* 800 Mbytes/sec */ - u8 rsv4:1; -#endif - } r; -}; - -struct sfp_xcvr_s { - union sfp_xcvr_e10g_code_u e10g; - union sfp_xcvr_so1_code_u so1; - union sfp_xcvr_so2_code_u so2; - union sfp_xcvr_eth_code_u eth; - struct sfp_xcvr_fc1_code_s fc1; - union sfp_xcvr_fc2_code_u fc2; - union sfp_xcvr_fc3_code_u fc3; -}; - -/* - * Flash module specific - */ -#define BFA_FLASH_PART_ENTRY_SIZE 32 /* partition entry size */ -#define BFA_FLASH_PART_MAX 32 /* maximal # of partitions */ - -enum bfa_flash_part_type { - BFA_FLASH_PART_OPTROM = 1, /* option rom partition */ - BFA_FLASH_PART_FWIMG = 2, /* firmware image partition */ - BFA_FLASH_PART_FWCFG = 3, /* firmware tuneable config */ - BFA_FLASH_PART_DRV = 4, /* IOC driver config */ - BFA_FLASH_PART_BOOT = 5, /* boot config */ - BFA_FLASH_PART_ASIC = 6, /* asic bootstrap configuration */ - BFA_FLASH_PART_MFG = 7, /* manufacturing block partition */ - BFA_FLASH_PART_OPTROM2 = 8, /* 2nd option rom partition */ - BFA_FLASH_PART_VPD = 9, /* vpd data of OEM info */ - BFA_FLASH_PART_PBC = 10, /* pre-boot config */ - BFA_FLASH_PART_BOOTOVL = 11, /* boot overlay partition */ - BFA_FLASH_PART_LOG = 12, /* firmware log partition */ - BFA_FLASH_PART_PXECFG = 13, /* pxe boot config partition */ - BFA_FLASH_PART_PXEOVL = 14, /* pxe boot overlay partition */ - BFA_FLASH_PART_PORTCFG = 15, /* port cfg partition */ - BFA_FLASH_PART_ASICBK = 16, /* asic backup partition */ -}; - -/* - * flash partition attributes - */ -struct bfa_flash_part_attr_s { - u32 part_type; /* partition type */ - u32 part_instance; /* partition instance */ - u32 part_off; /* partition offset */ - u32 part_size; /* partition size */ - u32 part_len; /* partition content length */ - u32 part_status; /* partition status */ - char rsv[BFA_FLASH_PART_ENTRY_SIZE - 24]; -}; - -/* - * flash attributes - */ -struct bfa_flash_attr_s { - u32 status; /* flash overall status */ - u32 npart; /* num of partitions */ - struct bfa_flash_part_attr_s part[BFA_FLASH_PART_MAX]; -}; - -/* - * DIAG module specific - */ -#define LB_PATTERN_DEFAULT 0xB5B5B5B5 -#define QTEST_CNT_DEFAULT 10 -#define QTEST_PAT_DEFAULT LB_PATTERN_DEFAULT - -struct bfa_diag_memtest_s { - u8 algo; - u8 rsvd[7]; -}; - -struct bfa_diag_memtest_result { - u32 status; - u32 addr; - u32 exp; /* expect value read from reg */ - u32 act; /* actually value read */ - u32 err_status; /* error status reg */ - u32 err_status1; /* extra error info reg */ - u32 err_addr; /* error address reg */ - u8 algo; - u8 rsv[3]; -}; - -struct bfa_diag_loopback_result_s { - u32 numtxmfrm; /* no. of transmit frame */ - u32 numosffrm; /* no. of outstanding frame */ - u32 numrcvfrm; /* no. of received good frame */ - u32 badfrminf; /* mis-match info */ - u32 badfrmnum; /* mis-match fram number */ - u8 status; /* loopback test result */ - u8 rsvd[3]; -}; - -struct bfa_diag_ledtest_s { - u32 cmd; /* bfa_led_op_t */ - u32 color; /* bfa_led_color_t */ - u16 freq; /* no. of blinks every 10 secs */ - u8 led; /* bitmap of LEDs to be tested */ - u8 rsvd[5]; -}; - -struct bfa_diag_loopback_s { - u32 loopcnt; - u32 pattern; - u8 lb_mode; /* bfa_port_opmode_t */ - u8 speed; /* bfa_port_speed_t */ - u8 rsvd[2]; -}; - -/* - * PHY module specific - */ -enum bfa_phy_status_e { - BFA_PHY_STATUS_GOOD = 0, /* phy is good */ - BFA_PHY_STATUS_NOT_PRESENT = 1, /* phy does not exist */ - BFA_PHY_STATUS_BAD = 2, /* phy is bad */ -}; - -/* - * phy attributes for phy query - */ -struct bfa_phy_attr_s { - u32 status; /* phy present/absent status */ - u32 length; /* firmware length */ - u32 fw_ver; /* firmware version */ - u32 an_status; /* AN status */ - u32 pma_pmd_status; /* PMA/PMD link status */ - u32 pma_pmd_signal; /* PMA/PMD signal detect */ - u32 pcs_status; /* PCS link status */ -}; - -/* - * phy stats - */ -struct bfa_phy_stats_s { - u32 status; /* phy stats status */ - u32 link_breaks; /* Num of link breaks after linkup */ - u32 pma_pmd_fault; /* NPMA/PMD fault */ - u32 pcs_fault; /* PCS fault */ - u32 speed_neg; /* Num of speed negotiation */ - u32 tx_eq_training; /* Num of TX EQ training */ - u32 tx_eq_timeout; /* Num of TX EQ timeout */ - u32 crc_error; /* Num of CRC errors */ -}; - -#pragma pack() - #endif /* __BFA_DEFS_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfa_defs_fcs.h b/trunk/drivers/scsi/bfa/bfa_defs_fcs.h index 3bbc583f65cf..191d34a58b9c 100644 --- a/trunk/drivers/scsi/bfa/bfa_defs_fcs.h +++ b/trunk/drivers/scsi/bfa/bfa_defs_fcs.h @@ -90,14 +90,12 @@ enum bfa_lport_role { * FCS port configuration. */ struct bfa_lport_cfg_s { - wwn_t pwwn; /* port wwn */ - wwn_t nwwn; /* node wwn */ - struct bfa_lport_symname_s sym_name; /* vm port symbolic name */ - enum bfa_lport_role roles; /* FCS port roles */ - u32 rsvd; - bfa_boolean_t preboot_vp; /* vport created from PBC */ - u8 tag[16]; /* opaque tag from application */ - u8 padding[4]; + wwn_t pwwn; /* port wwn */ + wwn_t nwwn; /* node wwn */ + struct bfa_lport_symname_s sym_name; /* vm port symbolic name */ + bfa_boolean_t preboot_vp; /* vport created from PBC */ + enum bfa_lport_role roles; /* FCS port roles */ + u8 tag[16]; /* opaque tag from application */ }; /* @@ -251,13 +249,12 @@ enum bfa_vport_state { BFA_FCS_VPORT_FDISC_SEND = 2, BFA_FCS_VPORT_FDISC = 3, BFA_FCS_VPORT_FDISC_RETRY = 4, - BFA_FCS_VPORT_FDISC_RSP_WAIT = 5, - BFA_FCS_VPORT_ONLINE = 6, - BFA_FCS_VPORT_DELETING = 7, - BFA_FCS_VPORT_CLEANUP = 8, - BFA_FCS_VPORT_LOGO_SEND = 9, - BFA_FCS_VPORT_LOGO = 10, - BFA_FCS_VPORT_ERROR = 11, + BFA_FCS_VPORT_ONLINE = 5, + BFA_FCS_VPORT_DELETING = 6, + BFA_FCS_VPORT_CLEANUP = 6, + BFA_FCS_VPORT_LOGO_SEND = 7, + BFA_FCS_VPORT_LOGO = 8, + BFA_FCS_VPORT_ERROR = 9, BFA_FCS_VPORT_MAX_STATE, }; diff --git a/trunk/drivers/scsi/bfa/bfa_defs_svc.h b/trunk/drivers/scsi/bfa/bfa_defs_svc.h index 0b97525803fb..207f598877c7 100644 --- a/trunk/drivers/scsi/bfa/bfa_defs_svc.h +++ b/trunk/drivers/scsi/bfa/bfa_defs_svc.h @@ -47,12 +47,13 @@ struct bfa_iocfc_fwcfg_s { u16 num_rports; /* number of remote ports */ u16 num_ioim_reqs; /* number of IO reqs */ u16 num_tskim_reqs; /* task management requests */ - u16 num_fwtio_reqs; /* number of TM IO reqs in FW */ + u16 num_iotm_reqs; /* number of TM IO reqs */ + u16 num_tsktm_reqs; /* TM task management requests*/ u16 num_fcxp_reqs; /* unassisted FC exchanges */ u16 num_uf_bufs; /* unsolicited recv buffers */ u8 num_cqs; u8 fw_tick_res; /* FW clock resolution in ms */ - u8 rsvd[2]; + u8 rsvd[4]; }; #pragma pack() @@ -65,12 +66,8 @@ struct bfa_iocfc_drvcfg_s { u16 ioc_recover; /* IOC recovery mode */ u16 min_cfg; /* minimum configuration */ u16 path_tov; /* device path timeout */ - u16 num_tio_reqs; /*!< number of TM IO reqs */ - u8 port_mode; - u8 rsvd_a; bfa_boolean_t delay_comp; /* delay completion of failed inflight IOs */ - u16 num_ttsk_reqs; /* TM task management requests */ u32 rsvd; }; @@ -85,7 +82,7 @@ struct bfa_iocfc_cfg_s { /* * IOC firmware IO stats */ -struct bfa_fw_ioim_stats_s { +struct bfa_fw_io_stats_s { u32 host_abort; /* IO aborted by host driver*/ u32 host_cleanup; /* IO clean up by host driver */ @@ -155,54 +152,6 @@ struct bfa_fw_ioim_stats_s { */ }; -struct bfa_fw_tio_stats_s { - u32 tio_conf_proc; /* TIO CONF processed */ - u32 tio_conf_drop; /* TIO CONF dropped */ - u32 tio_cleanup_req; /* TIO cleanup requested */ - u32 tio_cleanup_comp; /* TIO cleanup completed */ - u32 tio_abort_rsp; /* TIO abort response */ - u32 tio_abort_rsp_comp; /* TIO abort rsp completed */ - u32 tio_abts_req; /* TIO ABTS requested */ - u32 tio_abts_ack; /* TIO ABTS ack-ed */ - u32 tio_abts_ack_nocomp; /* TIO ABTS ack-ed but not completed */ - u32 tio_abts_tmo; /* TIO ABTS timeout */ - u32 tio_snsdata_dma; /* TIO sense data DMA */ - u32 tio_rxwchan_wait; /* TIO waiting for RX wait channel */ - u32 tio_rxwchan_avail; /* TIO RX wait channel available */ - u32 tio_hit_bls; /* TIO IOH BLS event */ - u32 tio_uf_recv; /* TIO received UF */ - u32 tio_rd_invalid_sm; /* TIO read reqst in wrong state machine */ - u32 tio_wr_invalid_sm;/* TIO write reqst in wrong state machine */ - - u32 ds_rxwchan_wait; /* DS waiting for RX wait channel */ - u32 ds_rxwchan_avail; /* DS RX wait channel available */ - u32 ds_unaligned_rd; /* DS unaligned read */ - u32 ds_rdcomp_invalid_sm; /* DS read completed in wrong state machine */ - u32 ds_wrcomp_invalid_sm; /* DS write completed in wrong state machine */ - u32 ds_flush_req; /* DS flush requested */ - u32 ds_flush_comp; /* DS flush completed */ - u32 ds_xfrdy_exp; /* DS XFER_RDY expired */ - u32 ds_seq_cnt_err; /* DS seq cnt error */ - u32 ds_seq_len_err; /* DS seq len error */ - u32 ds_data_oor; /* DS data out of order */ - u32 ds_hit_bls; /* DS hit BLS */ - u32 ds_edtov_timer_exp; /* DS edtov expired */ - u32 ds_cpu_owned; /* DS cpu owned */ - u32 ds_hit_class2; /* DS hit class2 */ - u32 ds_length_err; /* DS length error */ - u32 ds_ro_ooo_err; /* DS relative offset out-of-order error */ - u32 ds_rectov_timer_exp; /* DS rectov expired */ - u32 ds_unexp_fr_err; /* DS unexp frame error */ -}; - -/* - * IOC firmware IO stats - */ -struct bfa_fw_io_stats_s { - struct bfa_fw_ioim_stats_s ioim_stats; - struct bfa_fw_tio_stats_s tio_stats; -}; - /* * IOC port firmware stats */ @@ -256,7 +205,6 @@ struct bfa_fw_port_lksm_stats_s { u32 nos_tx; /* No. of times NOS tx started */ u32 hwsm_lrr_rx; /* No. of times LRR rx-ed by HWSM */ u32 hwsm_lr_rx; /* No. of times LR rx-ed by HWSM */ - u32 bbsc_lr; /* LKSM LR tx for credit recovery */ }; struct bfa_fw_port_snsm_stats_s { @@ -318,8 +266,8 @@ struct bfa_fw_fcoe_stats_s { * IOC firmware FCoE port stats */ struct bfa_fw_fcoe_port_stats_s { - struct bfa_fw_fcoe_stats_s fcoe_stats; - struct bfa_fw_fip_stats_s fip_stats; + struct bfa_fw_fcoe_stats_s fcoe_stats; + struct bfa_fw_fip_stats_s fip_stats; }; /* @@ -688,7 +636,6 @@ enum bfa_port_states { BFA_PORT_ST_FWMISMATCH = 12, BFA_PORT_ST_PREBOOT_DISABLED = 13, BFA_PORT_ST_TOGGLING_QWAIT = 14, - BFA_PORT_ST_ACQ_ADDR = 15, BFA_PORT_ST_MAX_STATE, }; @@ -801,10 +748,6 @@ struct bfa_port_cfg_s { u8 tx_bbcredit; /* transmit buffer credits */ u8 ratelimit; /* ratelimit enabled or not */ u8 trl_def_speed; /* ratelimit default speed */ - u8 bb_scn; /* BB_SCN value from FLOGI Exchg */ - u8 bb_scn_state; /* Config state of BB_SCN */ - u8 faa_state; /* FAA enabled/disabled */ - u8 rsvd[1]; u16 path_tov; /* device path timeout */ u16 q_depth; /* SCSI Queue depth */ }; @@ -840,7 +783,7 @@ struct bfa_port_attr_s { enum bfa_port_topology topology; /* current topology */ bfa_boolean_t beacon; /* current beacon status */ bfa_boolean_t link_e2e_beacon; /* link beacon is on */ - bfa_boolean_t bbsc_op_status; /* fc credit recovery oper state */ + bfa_boolean_t plog_enabled; /* portlog is enabled */ /* * Dynamic field - info from FCS @@ -849,10 +792,12 @@ struct bfa_port_attr_s { enum bfa_port_type port_type; /* current topology */ u32 loopback; /* external loopback */ u32 authfail; /* auth fail state */ + bfa_boolean_t io_profile; /* get it from fcpim mod */ + u8 pad[4]; /* for 64-bit alignement */ /* FCoE specific */ u16 fcoe_vlan; - u8 rsvd1[2]; + u8 rsvd1[6]; }; /* @@ -1042,19 +987,6 @@ struct bfa_itnim_ioprofile_s { struct bfa_itnim_latency_s io_latency; }; -/* - * vHBA port attribute values. - */ -struct bfa_vhba_attr_s { - wwn_t nwwn; /* node wwn */ - wwn_t pwwn; /* port wwn */ - u32 pid; /* port ID */ - bfa_boolean_t io_profile; /* get it from fcpim mod */ - bfa_boolean_t plog_enabled; /* portlog is enabled */ - u16 path_tov; - u8 rsvd[2]; -}; - /* * FC physical port statistics. */ @@ -1088,9 +1020,6 @@ struct bfa_port_fc_stats_s { u64 bad_os_count; /* Invalid ordered sets */ u64 err_enc_out; /* Encoding err nonframe_8b10b */ u64 err_enc; /* Encoding err frame_8b10b */ - u64 bbsc_frames_lost; /* Credit Recovery-Frames Lost */ - u64 bbsc_credits_lost; /* Credit Recovery-Credits Lost */ - u64 bbsc_link_resets; /* Credit Recovery-Link Resets */ }; /* @@ -1149,83 +1078,4 @@ union bfa_port_stats_u { struct bfa_port_eth_stats_s eth; }; -struct bfa_port_cfg_mode_s { - u16 max_pf; - u16 max_vf; - enum bfa_mode_s mode; -}; - -#pragma pack(1) - -#define BFA_CEE_LLDP_MAX_STRING_LEN (128) -#define BFA_CEE_DCBX_MAX_PRIORITY (8) -#define BFA_CEE_DCBX_MAX_PGID (8) - -struct bfa_cee_lldp_str_s { - u8 sub_type; - u8 len; - u8 rsvd[2]; - u8 value[BFA_CEE_LLDP_MAX_STRING_LEN]; -}; - -struct bfa_cee_lldp_cfg_s { - struct bfa_cee_lldp_str_s chassis_id; - struct bfa_cee_lldp_str_s port_id; - struct bfa_cee_lldp_str_s port_desc; - struct bfa_cee_lldp_str_s sys_name; - struct bfa_cee_lldp_str_s sys_desc; - struct bfa_cee_lldp_str_s mgmt_addr; - u16 time_to_live; - u16 enabled_system_cap; -}; - -/* CEE/DCBX parameters */ -struct bfa_cee_dcbx_cfg_s { - u8 pgid[BFA_CEE_DCBX_MAX_PRIORITY]; - u8 pg_percentage[BFA_CEE_DCBX_MAX_PGID]; - u8 pfc_primap; /* bitmap of priorties with PFC enabled */ - u8 fcoe_primap; /* bitmap of priorities used for FcoE traffic */ - u8 iscsi_primap; /* bitmap of priorities used for iSCSI traffic */ - u8 dcbx_version; /* operating version:CEE or preCEE */ - u8 lls_fcoe; /* FCoE Logical Link Status */ - u8 lls_lan; /* LAN Logical Link Status */ - u8 rsvd[2]; -}; - -/* CEE Query */ -struct bfa_cee_attr_s { - u8 cee_status; - u8 error_reason; - struct bfa_cee_lldp_cfg_s lldp_remote; - struct bfa_cee_dcbx_cfg_s dcbx_remote; - mac_t src_mac; - u8 link_speed; - u8 nw_priority; - u8 filler[2]; -}; - -/* LLDP/DCBX/CEE Statistics */ -struct bfa_cee_stats_s { - u32 lldp_tx_frames; /* LLDP Tx Frames */ - u32 lldp_rx_frames; /* LLDP Rx Frames */ - u32 lldp_rx_frames_invalid; /* LLDP Rx Frames invalid */ - u32 lldp_rx_frames_new; /* LLDP Rx Frames new */ - u32 lldp_tlvs_unrecognized; /* LLDP Rx unrecog. TLVs */ - u32 lldp_rx_shutdown_tlvs; /* LLDP Rx shutdown TLVs */ - u32 lldp_info_aged_out; /* LLDP remote info aged */ - u32 dcbx_phylink_ups; /* DCBX phy link ups */ - u32 dcbx_phylink_downs; /* DCBX phy link downs */ - u32 dcbx_rx_tlvs; /* DCBX Rx TLVs */ - u32 dcbx_rx_tlvs_invalid; /* DCBX Rx TLVs invalid */ - u32 dcbx_control_tlv_error; /* DCBX control TLV errors */ - u32 dcbx_feature_tlv_error; /* DCBX feature TLV errors */ - u32 dcbx_cee_cfg_new; /* DCBX new CEE cfg rcvd */ - u32 cee_status_down; /* DCB status down */ - u32 cee_status_up; /* DCB status up */ - u32 cee_hw_cfg_changed; /* DCB hw cfg changed */ - u32 cee_rx_invalid_cfg; /* DCB invalid cfg */ -}; - -#pragma pack() - #endif /* __BFA_DEFS_SVC_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfa_fc.h b/trunk/drivers/scsi/bfa/bfa_fc.h index 8d0b88f67a38..bf0067e0fd0d 100644 --- a/trunk/drivers/scsi/bfa/bfa_fc.h +++ b/trunk/drivers/scsi/bfa/bfa_fc.h @@ -1021,7 +1021,7 @@ struct fc_symname_s { #define FC_ED_TOV 2 #define FC_REC_TOV (FC_ED_TOV + 1) #define FC_RA_TOV 10 -#define FC_ELS_TOV ((2 * FC_RA_TOV) + 1) +#define FC_ELS_TOV (2 * FC_RA_TOV) #define FC_FCCT_TOV (3 * FC_RA_TOV) /* @@ -1048,6 +1048,15 @@ struct fc_vft_s { u32 res_c:24; }; +/* + * FCP + */ +enum { + FCP_RJT = 0x01000000, /* SRR reject */ + FCP_SRR_ACCEPT = 0x02000000, /* SRR accept */ + FCP_SRR = 0x14000000, /* Sequence Retransmission Request */ +}; + /* * FCP_CMND definitions */ diff --git a/trunk/drivers/scsi/bfa/bfa_fcbuild.c b/trunk/drivers/scsi/bfa/bfa_fcbuild.c index 17b59b8b5644..b7e253451654 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcbuild.c +++ b/trunk/drivers/scsi/bfa/bfa_fcbuild.c @@ -94,6 +94,7 @@ fcbuild_init(void) */ plogi_tmpl.csp.verhi = FC_PH_VER_PH_3; plogi_tmpl.csp.verlo = FC_PH_VER_4_3; + plogi_tmpl.csp.bbcred = cpu_to_be16(0x0004); plogi_tmpl.csp.ciro = 0x1; plogi_tmpl.csp.cisc = 0x0; plogi_tmpl.csp.altbbcred = 0x0; @@ -155,22 +156,6 @@ fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u32 ox_id) */ } -static void -fc_gsresp_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id) -{ - memset(fchs, 0, sizeof(struct fchs_s)); - - fchs->routing = FC_RTG_FC4_DEV_DATA; - fchs->cat_info = FC_CAT_SOLICIT_CTRL; - fchs->type = FC_TYPE_SERVICES; - fchs->f_ctl = - bfa_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH | - FCTL_END_SEQ | FCTL_SI_XFER); - fchs->d_id = d_id; - fchs->s_id = s_id; - fchs->ox_id = ox_id; -} - void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id) { @@ -222,7 +207,7 @@ fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id) static u16 fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr, u8 els_code) + u16 pdu_size, u8 els_code) { struct fc_logi_s *plogi = (struct fc_logi_s *) (pld); @@ -235,7 +220,6 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, fc_els_rsp_build(fchs, d_id, s_id, ox_id); plogi->csp.rxsz = plogi->class3.rxsz = cpu_to_be16(pdu_size); - plogi->csp.bbcred = cpu_to_be16(bb_cr); memcpy(&plogi->port_name, &port_name, sizeof(wwn_t)); memcpy(&plogi->node_name, &node_name, sizeof(wwn_t)); @@ -284,17 +268,15 @@ fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 local_bb_credits, u8 bb_scn) + u16 pdu_size, u16 local_bb_credits) { u32 d_id = 0; - u16 bbscn_rxsz = (bb_scn << 12) | pdu_size; memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); fc_els_rsp_build(fchs, d_id, s_id, ox_id); flogi->els_cmd.els_code = FC_ELS_ACC; - flogi->class3.rxsz = cpu_to_be16(pdu_size); - flogi->csp.rxsz = cpu_to_be16(bbscn_rxsz); /* bb_scn/rxsz */ + flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size); flogi->port_name = port_name; flogi->node_name = node_name; @@ -324,19 +306,19 @@ fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr) + u16 pdu_size) { return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name, - node_name, pdu_size, bb_cr, FC_ELS_PLOGI); + node_name, pdu_size, FC_ELS_PLOGI); } u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr) + u16 pdu_size) { return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name, - node_name, pdu_size, bb_cr, FC_ELS_ACC); + node_name, pdu_size, FC_ELS_ACC); } enum fc_parse_status @@ -1113,21 +1095,6 @@ fc_ct_rsp_parse(struct ct_hdr_s *cthdr) return FC_PARSE_OK; } -u16 -fc_gs_rjt_build(struct fchs_s *fchs, struct ct_hdr_s *cthdr, - u32 d_id, u32 s_id, u16 ox_id, u8 reason_code, - u8 reason_code_expl) -{ - fc_gsresp_fchdr_build(fchs, d_id, s_id, ox_id); - - cthdr->cmd_rsp_code = cpu_to_be16(CT_RSP_REJECT); - cthdr->rev_id = CT_GS3_REVISION; - - cthdr->reason_code = reason_code; - cthdr->exp_code = reason_code_expl; - return sizeof(struct ct_hdr_s); -} - u16 fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg, u32 s_id, u16 ox_id) diff --git a/trunk/drivers/scsi/bfa/bfa_fcbuild.h b/trunk/drivers/scsi/bfa/bfa_fcbuild.h index 42cd9d4da697..ece51ec7620b 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcbuild.h +++ b/trunk/drivers/scsi/bfa/bfa_fcbuild.h @@ -66,9 +66,6 @@ fc_rpsc_operspeed_to_bfa_speed(enum fc_rpsc_op_speed speed) case RPSC_OP_SPEED_8G: return BFA_PORT_SPEED_8GBPS; - case RPSC_OP_SPEED_16G: - return BFA_PORT_SPEED_16GBPS; - case RPSC_OP_SPEED_10G: return BFA_PORT_SPEED_10GBPS; @@ -97,9 +94,6 @@ fc_bfa_speed_to_rpsc_operspeed(enum bfa_port_speed op_speed) case BFA_PORT_SPEED_8GBPS: return RPSC_OP_SPEED_8G; - case BFA_PORT_SPEED_16GBPS: - return RPSC_OP_SPEED_16G; - case BFA_PORT_SPEED_10GBPS: return RPSC_OP_SPEED_10G; @@ -147,11 +141,11 @@ u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size, - u16 local_bb_credits, u8 bb_scn); + u16 local_bb_credits); u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, - wwn_t node_name, u16 pdu_size, u16 bb_cr); + wwn_t node_name, u16 pdu_size); enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs); @@ -183,17 +177,13 @@ u16 fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 fc_gpnid_build(struct fchs_s *fchs, void *pld, u32 s_id, u16 ox_id, u32 port_id); -u16 fc_gs_rjt_build(struct fchs_s *fchs, struct ct_hdr_s *cthdr, - u32 d_id, u32 s_id, u16 ox_id, - u8 reason_code, u8 reason_code_expl); - u16 fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg, u32 s_id, u16 ox_id); u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr); + u16 pdu_size); u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, u32 s_id, __be16 ox_id, wwn_t port_name, diff --git a/trunk/drivers/scsi/bfa/bfa_fcpim.c b/trunk/drivers/scsi/bfa/bfa_fcpim.c index a4e7951c6063..c0353cdca929 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcpim.c +++ b/trunk/drivers/scsi/bfa/bfa_fcpim.c @@ -19,6 +19,7 @@ #include "bfa_modules.h" BFA_TRC_FILE(HAL, FCPIM); +BFA_MODULE(fcpim); /* * BFA ITNIM Related definitions @@ -286,16 +287,24 @@ static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, * Compute and return memory needed by FCP(im) module. */ static void -bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len) +bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) { - bfa_itnim_meminfo(cfg, km_len); + bfa_itnim_meminfo(cfg, km_len, dm_len); /* * IO memory */ + if (cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN) + cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN; + else if (cfg->fwcfg.num_ioim_reqs > BFA_IOIM_MAX) + cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX; + *km_len += cfg->fwcfg.num_ioim_reqs * (sizeof(struct bfa_ioim_s) + sizeof(struct bfa_ioim_sp_s)); + *dm_len += cfg->fwcfg.num_ioim_reqs * BFI_IOIM_SNSLEN; + /* * task management command memory */ @@ -306,41 +315,52 @@ bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len) static void -bfa_fcpim_attach(struct bfa_fcp_mod_s *fcp, void *bfad, - struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) +bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { - struct bfa_fcpim_s *fcpim = &fcp->fcpim; - struct bfa_s *bfa = fcp->bfa; + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); bfa_trc(bfa, cfg->drvcfg.path_tov); bfa_trc(bfa, cfg->fwcfg.num_rports); bfa_trc(bfa, cfg->fwcfg.num_ioim_reqs); bfa_trc(bfa, cfg->fwcfg.num_tskim_reqs); - fcpim->fcp = fcp; fcpim->bfa = bfa; fcpim->num_itnims = cfg->fwcfg.num_rports; + fcpim->num_ioim_reqs = cfg->fwcfg.num_ioim_reqs; fcpim->num_tskim_reqs = cfg->fwcfg.num_tskim_reqs; fcpim->path_tov = cfg->drvcfg.path_tov; fcpim->delay_comp = cfg->drvcfg.delay_comp; fcpim->profile_comp = NULL; fcpim->profile_start = NULL; - bfa_itnim_attach(fcpim); - bfa_tskim_attach(fcpim); - bfa_ioim_attach(fcpim); + bfa_itnim_attach(fcpim, meminfo); + bfa_tskim_attach(fcpim, meminfo); + bfa_ioim_attach(fcpim, meminfo); +} + +static void +bfa_fcpim_detach(struct bfa_s *bfa) +{ +} + +static void +bfa_fcpim_start(struct bfa_s *bfa) +{ } static void -bfa_fcpim_iocdisable(struct bfa_fcp_mod_s *fcp) +bfa_fcpim_stop(struct bfa_s *bfa) { - struct bfa_fcpim_s *fcpim = &fcp->fcpim; +} + +static void +bfa_fcpim_iocdisable(struct bfa_s *bfa) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfa_itnim_s *itnim; struct list_head *qe, *qen; - /* Enqueue unused ioim resources to free_q */ - list_splice_tail_init(&fcpim->tskim_unused_q, &fcpim->tskim_free_q); - list_for_each_safe(qe, qen, &fcpim->itnim_q) { itnim = (struct bfa_itnim_s *) qe; bfa_itnim_iocdisable(itnim); @@ -350,7 +370,7 @@ bfa_fcpim_iocdisable(struct bfa_fcp_mod_s *fcp) void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); fcpim->path_tov = path_tov * 1000; if (fcpim->path_tov > BFA_FCPIM_PATHTOV_MAX) @@ -360,87 +380,15 @@ bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov) u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); return fcpim->path_tov / 1000; } -#define bfa_fcpim_add_iostats(__l, __r, __stats) \ - (__l->__stats += __r->__stats) - -void -bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats, - struct bfa_itnim_iostats_s *rstats) -{ - bfa_fcpim_add_iostats(lstats, rstats, total_ios); - bfa_fcpim_add_iostats(lstats, rstats, qresumes); - bfa_fcpim_add_iostats(lstats, rstats, no_iotags); - bfa_fcpim_add_iostats(lstats, rstats, io_aborts); - bfa_fcpim_add_iostats(lstats, rstats, no_tskims); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_ok); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_underrun); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_overrun); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_aborted); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_timedout); - bfa_fcpim_add_iostats(lstats, rstats, iocom_nexus_abort); - bfa_fcpim_add_iostats(lstats, rstats, iocom_proto_err); - bfa_fcpim_add_iostats(lstats, rstats, iocom_dif_err); - bfa_fcpim_add_iostats(lstats, rstats, iocom_sqer_needed); - bfa_fcpim_add_iostats(lstats, rstats, iocom_res_free); - bfa_fcpim_add_iostats(lstats, rstats, iocom_hostabrts); - bfa_fcpim_add_iostats(lstats, rstats, iocom_utags); - bfa_fcpim_add_iostats(lstats, rstats, io_cleanups); - bfa_fcpim_add_iostats(lstats, rstats, io_tmaborts); - bfa_fcpim_add_iostats(lstats, rstats, onlines); - bfa_fcpim_add_iostats(lstats, rstats, offlines); - bfa_fcpim_add_iostats(lstats, rstats, creates); - bfa_fcpim_add_iostats(lstats, rstats, deletes); - bfa_fcpim_add_iostats(lstats, rstats, create_comps); - bfa_fcpim_add_iostats(lstats, rstats, delete_comps); - bfa_fcpim_add_iostats(lstats, rstats, sler_events); - bfa_fcpim_add_iostats(lstats, rstats, fw_create); - bfa_fcpim_add_iostats(lstats, rstats, fw_delete); - bfa_fcpim_add_iostats(lstats, rstats, ioc_disabled); - bfa_fcpim_add_iostats(lstats, rstats, cleanup_comps); - bfa_fcpim_add_iostats(lstats, rstats, tm_cmnds); - bfa_fcpim_add_iostats(lstats, rstats, tm_fw_rsps); - bfa_fcpim_add_iostats(lstats, rstats, tm_success); - bfa_fcpim_add_iostats(lstats, rstats, tm_failures); - bfa_fcpim_add_iostats(lstats, rstats, tm_io_comps); - bfa_fcpim_add_iostats(lstats, rstats, tm_qresumes); - bfa_fcpim_add_iostats(lstats, rstats, tm_iocdowns); - bfa_fcpim_add_iostats(lstats, rstats, tm_cleanups); - bfa_fcpim_add_iostats(lstats, rstats, tm_cleanup_comps); - bfa_fcpim_add_iostats(lstats, rstats, io_comps); - bfa_fcpim_add_iostats(lstats, rstats, input_reqs); - bfa_fcpim_add_iostats(lstats, rstats, output_reqs); - bfa_fcpim_add_iostats(lstats, rstats, rd_throughput); - bfa_fcpim_add_iostats(lstats, rstats, wr_throughput); -} - -bfa_status_t -bfa_fcpim_port_iostats(struct bfa_s *bfa, - struct bfa_itnim_iostats_s *stats, u8 lp_tag) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct list_head *qe, *qen; - struct bfa_itnim_s *itnim; - - /* accumulate IO stats from itnim */ - memset(stats, 0, sizeof(struct bfa_itnim_iostats_s)); - list_for_each_safe(qe, qen, &fcpim->itnim_q) { - itnim = (struct bfa_itnim_s *) qe; - if (itnim->rport->rport_info.lp_tag != lp_tag) - continue; - bfa_fcpim_add_stats(stats, &(itnim->stats)); - } - return BFA_STATUS_OK; -} - u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); return fcpim->q_depth; } @@ -1042,7 +990,8 @@ bfa_itnim_tskdone(struct bfa_itnim_s *itnim) } void -bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len) +bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) { /* * ITN memory @@ -1051,16 +1000,15 @@ bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len) } void -bfa_itnim_attach(struct bfa_fcpim_s *fcpim) +bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) { struct bfa_s *bfa = fcpim->bfa; - struct bfa_fcp_mod_s *fcp = fcpim->fcp; struct bfa_itnim_s *itnim; int i, j; INIT_LIST_HEAD(&fcpim->itnim_q); - itnim = (struct bfa_itnim_s *) bfa_mem_kva_curp(fcp); + itnim = (struct bfa_itnim_s *) bfa_meminfo_kva(minfo); fcpim->itnim_arr = itnim; for (i = 0; i < fcpim->num_itnims; i++, itnim++) { @@ -1082,7 +1030,7 @@ bfa_itnim_attach(struct bfa_fcpim_s *fcpim) bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); } - bfa_mem_kva_curp(fcp) = (u8 *) itnim; + bfa_meminfo_kva(minfo) = (u8 *) itnim; } void @@ -1095,7 +1043,7 @@ bfa_itnim_iocdisable(struct bfa_itnim_s *itnim) static bfa_boolean_t bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim) { - struct bfi_itn_create_req_s *m; + struct bfi_itnim_create_req_s *m; itnim->msg_no++; @@ -1108,8 +1056,8 @@ bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim) return BFA_FALSE; } - bfi_h2i_set(m->mh, BFI_MC_ITN, BFI_ITN_H2I_CREATE_REQ, - bfa_fn_lpu(itnim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_CREATE_REQ, + bfa_lpuid(itnim->bfa)); m->fw_handle = itnim->rport->fw_handle; m->class = FC_CLASS_3; m->seq_rec = itnim->seq_rec; @@ -1119,14 +1067,14 @@ bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim) /* * queue I/O message to firmware */ - bfa_reqq_produce(itnim->bfa, itnim->reqq, m->mh); + bfa_reqq_produce(itnim->bfa, itnim->reqq); return BFA_TRUE; } static bfa_boolean_t bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim) { - struct bfi_itn_delete_req_s *m; + struct bfi_itnim_delete_req_s *m; /* * check for room in queue to send request now @@ -1137,15 +1085,15 @@ bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim) return BFA_FALSE; } - bfi_h2i_set(m->mh, BFI_MC_ITN, BFI_ITN_H2I_DELETE_REQ, - bfa_fn_lpu(itnim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_DELETE_REQ, + bfa_lpuid(itnim->bfa)); m->fw_handle = itnim->rport->fw_handle; bfa_stats(itnim, fw_delete); /* * queue I/O message to firmware */ - bfa_reqq_produce(itnim->bfa, itnim->reqq, m->mh); + bfa_reqq_produce(itnim->bfa, itnim->reqq); return BFA_TRUE; } @@ -1276,7 +1224,7 @@ bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim) static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(itnim->bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(itnim->bfa); fcpim->del_itn_stats.del_itn_iocomp_aborted += itnim->stats.iocomp_aborted; fcpim->del_itn_stats.del_itn_iocomp_timedout += @@ -1302,8 +1250,8 @@ bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim) void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - union bfi_itn_i2h_msg_u msg; + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + union bfi_itnim_i2h_msg_u msg; struct bfa_itnim_s *itnim; bfa_trc(bfa, m->mhdr.msg_id); @@ -1311,7 +1259,7 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) msg.msg = m; switch (m->mhdr.msg_id) { - case BFI_ITN_I2H_CREATE_RSP: + case BFI_ITNIM_I2H_CREATE_RSP: itnim = BFA_ITNIM_FROM_TAG(fcpim, msg.create_rsp->bfa_handle); WARN_ON(msg.create_rsp->status != BFA_STATUS_OK); @@ -1319,7 +1267,7 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); break; - case BFI_ITN_I2H_DELETE_RSP: + case BFI_ITNIM_I2H_DELETE_RSP: itnim = BFA_ITNIM_FROM_TAG(fcpim, msg.delete_rsp->bfa_handle); WARN_ON(msg.delete_rsp->status != BFA_STATUS_OK); @@ -1327,7 +1275,7 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); break; - case BFI_ITN_I2H_SLER_EVENT: + case BFI_ITNIM_I2H_SLER_EVENT: itnim = BFA_ITNIM_FROM_TAG(fcpim, msg.sler_event->bfa_handle); bfa_stats(itnim, sler_events); @@ -1347,11 +1295,9 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) struct bfa_itnim_s * bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfa_itnim_s *itnim; - bfa_itn_create(bfa, rport, bfa_itnim_isr); - itnim = BFA_ITNIM_FROM_TAG(fcpim, rport->rport_tag); WARN_ON(itnim->rport != rport); @@ -2045,8 +1991,7 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete) if ((m->scsi_status == SCSI_STATUS_CHECK_CONDITION) && m->sns_len) { sns_len = m->sns_len; - snsinfo = BFA_SNSINFO_FROM_TAG(ioim->fcpim->fcp, - ioim->iotag); + snsinfo = ioim->iosp->snsinfo; } /* @@ -2244,12 +2189,12 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) */ switch (m->cmnd.iodir) { case FCP_IODIR_READ: - bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_fn_lpu(ioim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_lpuid(ioim->bfa)); bfa_stats(itnim, input_reqs); ioim->itnim->stats.rd_throughput += fcp_dl; break; case FCP_IODIR_WRITE: - bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_fn_lpu(ioim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_lpuid(ioim->bfa)); bfa_stats(itnim, output_reqs); ioim->itnim->stats.wr_throughput += fcp_dl; break; @@ -2257,16 +2202,16 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) bfa_stats(itnim, input_reqs); bfa_stats(itnim, output_reqs); default: - bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_fn_lpu(ioim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa)); } if (itnim->seq_rec || (scsi_bufflen(cmnd) & (sizeof(u32) - 1))) - bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_fn_lpu(ioim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa)); /* * queue I/O message to firmware */ - bfa_reqq_produce(ioim->bfa, ioim->reqq, m->mh); + bfa_reqq_produce(ioim->bfa, ioim->reqq); return BFA_TRUE; } @@ -2324,14 +2269,14 @@ bfa_ioim_send_abort(struct bfa_ioim_s *ioim) else msgop = BFI_IOIM_H2I_IOCLEANUP_REQ; - bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_fn_lpu(ioim->bfa)); + bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_lpuid(ioim->bfa)); m->io_tag = cpu_to_be16(ioim->iotag); m->abort_tag = ++ioim->abort_tag; /* * queue I/O message to firmware */ - bfa_reqq_produce(ioim->bfa, ioim->reqq, m->mh); + bfa_reqq_produce(ioim->bfa, ioim->reqq); return BFA_TRUE; } @@ -2415,32 +2360,46 @@ bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov) * Memory allocation and initialization. */ void -bfa_ioim_attach(struct bfa_fcpim_s *fcpim) +bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) { struct bfa_ioim_s *ioim; - struct bfa_fcp_mod_s *fcp = fcpim->fcp; struct bfa_ioim_sp_s *iosp; u16 i; + u8 *snsinfo; + u32 snsbufsz; /* * claim memory first */ - ioim = (struct bfa_ioim_s *) bfa_mem_kva_curp(fcp); + ioim = (struct bfa_ioim_s *) bfa_meminfo_kva(minfo); fcpim->ioim_arr = ioim; - bfa_mem_kva_curp(fcp) = (u8 *) (ioim + fcpim->fcp->num_ioim_reqs); + bfa_meminfo_kva(minfo) = (u8 *) (ioim + fcpim->num_ioim_reqs); - iosp = (struct bfa_ioim_sp_s *) bfa_mem_kva_curp(fcp); + iosp = (struct bfa_ioim_sp_s *) bfa_meminfo_kva(minfo); fcpim->ioim_sp_arr = iosp; - bfa_mem_kva_curp(fcp) = (u8 *) (iosp + fcpim->fcp->num_ioim_reqs); + bfa_meminfo_kva(minfo) = (u8 *) (iosp + fcpim->num_ioim_reqs); + + /* + * Claim DMA memory for per IO sense data. + */ + snsbufsz = fcpim->num_ioim_reqs * BFI_IOIM_SNSLEN; + fcpim->snsbase.pa = bfa_meminfo_dma_phys(minfo); + bfa_meminfo_dma_phys(minfo) += snsbufsz; + + fcpim->snsbase.kva = bfa_meminfo_dma_virt(minfo); + bfa_meminfo_dma_virt(minfo) += snsbufsz; + snsinfo = fcpim->snsbase.kva; + bfa_iocfc_set_snsbase(fcpim->bfa, fcpim->snsbase.pa); /* * Initialize ioim free queues */ + INIT_LIST_HEAD(&fcpim->ioim_free_q); INIT_LIST_HEAD(&fcpim->ioim_resfree_q); INIT_LIST_HEAD(&fcpim->ioim_comp_q); - for (i = 0; i < fcpim->fcp->num_ioim_reqs; - i++, ioim++, iosp++) { + for (i = 0; i < fcpim->num_ioim_reqs; + i++, ioim++, iosp++, snsinfo += BFI_IOIM_SNSLEN) { /* * initialize IOIM */ @@ -2449,19 +2408,22 @@ bfa_ioim_attach(struct bfa_fcpim_s *fcpim) ioim->bfa = fcpim->bfa; ioim->fcpim = fcpim; ioim->iosp = iosp; + iosp->snsinfo = snsinfo; INIT_LIST_HEAD(&ioim->sgpg_q); bfa_reqq_winit(&ioim->iosp->reqq_wait, bfa_ioim_qresume, ioim); bfa_sgpg_winit(&ioim->iosp->sgpg_wqe, bfa_ioim_sgpg_alloced, ioim); bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); + + list_add_tail(&ioim->qe, &fcpim->ioim_free_q); } } void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; struct bfa_ioim_s *ioim; u16 iotag; @@ -2545,7 +2507,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) void bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; struct bfa_ioim_s *ioim; u16 iotag; @@ -2611,21 +2573,18 @@ struct bfa_ioim_s * bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio, struct bfa_itnim_s *itnim, u16 nsges) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfa_ioim_s *ioim; - struct bfa_iotag_s *iotag = NULL; /* * alocate IOIM resource */ - bfa_q_deq(&fcpim->fcp->iotag_ioim_free_q, &iotag); - if (!iotag) { + bfa_q_deq(&fcpim->ioim_free_q, &ioim); + if (!ioim) { bfa_stats(itnim, no_iotags); return NULL; } - ioim = BFA_IOIM_FROM_TAG(fcpim, iotag->tag); - ioim->dio = dio; ioim->itnim = itnim; ioim->nsges = nsges; @@ -2642,8 +2601,7 @@ bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio, void bfa_ioim_free(struct bfa_ioim_s *ioim) { - struct bfa_fcpim_s *fcpim = ioim->fcpim; - struct bfa_iotag_s *iotag; + struct bfa_fcpim_mod_s *fcpim = ioim->fcpim; if (ioim->nsgpgs > 0) bfa_sgpg_mfree(ioim->bfa, &ioim->sgpg_q, ioim->nsgpgs); @@ -2652,17 +2610,8 @@ bfa_ioim_free(struct bfa_ioim_s *ioim) fcpim->ios_active--; ioim->iotag &= BFA_IOIM_IOTAG_MASK; - - WARN_ON(!(ioim->iotag < - (fcpim->fcp->num_ioim_reqs + fcpim->fcp->num_fwtio_reqs))); - iotag = BFA_IOTAG_FROM_TAG(fcpim->fcp, ioim->iotag); - - if (ioim->iotag < fcpim->fcp->num_ioim_reqs) - list_add_tail(&iotag->qe, &fcpim->fcp->iotag_ioim_free_q); - else - list_add_tail(&iotag->qe, &fcpim->fcp->iotag_tio_free_q); - list_del(&ioim->qe); + list_add_tail(&ioim->qe, &fcpim->ioim_free_q); } void @@ -3072,7 +3021,7 @@ bfa_tskim_send(struct bfa_tskim_s *tskim) * build i/o request message next */ bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ, - bfa_fn_lpu(tskim->bfa)); + bfa_lpuid(tskim->bfa)); m->tsk_tag = cpu_to_be16(tskim->tsk_tag); m->itn_fhdl = tskim->itnim->rport->fw_handle; @@ -3083,7 +3032,7 @@ bfa_tskim_send(struct bfa_tskim_s *tskim) /* * queue I/O message to firmware */ - bfa_reqq_produce(tskim->bfa, itnim->reqq, m->mh); + bfa_reqq_produce(tskim->bfa, itnim->reqq); return BFA_TRUE; } @@ -3107,14 +3056,14 @@ bfa_tskim_send_abort(struct bfa_tskim_s *tskim) * build i/o request message next */ bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ, - bfa_fn_lpu(tskim->bfa)); + bfa_lpuid(tskim->bfa)); m->tsk_tag = cpu_to_be16(tskim->tsk_tag); /* * queue I/O message to firmware */ - bfa_reqq_produce(tskim->bfa, itnim->reqq, m->mh); + bfa_reqq_produce(tskim->bfa, itnim->reqq); return BFA_TRUE; } @@ -3180,16 +3129,14 @@ bfa_tskim_cleanup(struct bfa_tskim_s *tskim) * Memory allocation and initialization. */ void -bfa_tskim_attach(struct bfa_fcpim_s *fcpim) +bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) { struct bfa_tskim_s *tskim; - struct bfa_fcp_mod_s *fcp = fcpim->fcp; u16 i; INIT_LIST_HEAD(&fcpim->tskim_free_q); - INIT_LIST_HEAD(&fcpim->tskim_unused_q); - tskim = (struct bfa_tskim_s *) bfa_mem_kva_curp(fcp); + tskim = (struct bfa_tskim_s *) bfa_meminfo_kva(minfo); fcpim->tskim_arr = tskim; for (i = 0; i < fcpim->num_tskim_reqs; i++, tskim++) { @@ -3208,13 +3155,13 @@ bfa_tskim_attach(struct bfa_fcpim_s *fcpim) list_add_tail(&tskim->qe, &fcpim->tskim_free_q); } - bfa_mem_kva_curp(fcp) = (u8 *) tskim; + bfa_meminfo_kva(minfo) = (u8 *) tskim; } void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m; struct bfa_tskim_s *tskim; u16 tsk_tag = be16_to_cpu(rsp->tsk_tag); @@ -3241,7 +3188,7 @@ bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) struct bfa_tskim_s * bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk) { - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfa_tskim_s *tskim; bfa_q_deq(&fcpim->tskim_free_q, &tskim); @@ -3286,214 +3233,3 @@ bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, list_add_tail(&tskim->qe, &itnim->tsk_q); bfa_sm_send_event(tskim, BFA_TSKIM_SM_START); } - -void -bfa_tskim_res_recfg(struct bfa_s *bfa, u16 num_tskim_fw) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (fcpim->num_tskim_reqs - num_tskim_fw); i++) { - bfa_q_deq_tail(&fcpim->tskim_free_q, &qe); - list_add_tail(qe, &fcpim->tskim_unused_q); - } -} - -/* BFA FCP module - parent module for fcpim */ - -BFA_MODULE(fcp); - -static void -bfa_fcp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - struct bfa_mem_kva_s *fcp_kva = BFA_MEM_FCP_KVA(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_ios, num_io_req; - u32 km_len = 0; - - /* - * ZERO for num_ioim_reqs and num_fwtio_reqs is allowed config value. - * So if the values are non zero, adjust them appropriately. - */ - if (cfg->fwcfg.num_ioim_reqs && - cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN) - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN; - else if (cfg->fwcfg.num_ioim_reqs > BFA_IOIM_MAX) - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX; - - if (cfg->fwcfg.num_fwtio_reqs > BFA_FWTIO_MAX) - cfg->fwcfg.num_fwtio_reqs = BFA_FWTIO_MAX; - - num_io_req = (cfg->fwcfg.num_ioim_reqs + cfg->fwcfg.num_fwtio_reqs); - if (num_io_req > BFA_IO_MAX) { - if (cfg->fwcfg.num_ioim_reqs && cfg->fwcfg.num_fwtio_reqs) { - cfg->fwcfg.num_ioim_reqs = BFA_IO_MAX/2; - cfg->fwcfg.num_fwtio_reqs = BFA_IO_MAX/2; - } else if (cfg->fwcfg.num_fwtio_reqs) - cfg->fwcfg.num_fwtio_reqs = BFA_FWTIO_MAX; - else - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX; - } - - bfa_fcpim_meminfo(cfg, &km_len); - - num_io_req = (cfg->fwcfg.num_ioim_reqs + cfg->fwcfg.num_fwtio_reqs); - km_len += num_io_req * sizeof(struct bfa_iotag_s); - km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itn_s); - - /* dma memory */ - nsegs = BFI_MEM_DMA_NSEGS(num_io_req, BFI_IOIM_SNSLEN); - per_seg_ios = BFI_MEM_NREQS_SEG(BFI_IOIM_SNSLEN); - - bfa_mem_dma_seg_iter(fcp, seg_ptr, nsegs, idx) { - if (num_io_req >= per_seg_ios) { - num_io_req -= per_seg_ios; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_ios * BFI_IOIM_SNSLEN); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_io_req * BFI_IOIM_SNSLEN); - } - - /* kva memory */ - bfa_mem_kva_setup(minfo, fcp_kva, km_len); -} - -static void -bfa_fcp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 idx, nsegs, num_io_req; - - fcp->num_ioim_reqs = cfg->fwcfg.num_ioim_reqs; - fcp->num_fwtio_reqs = cfg->fwcfg.num_fwtio_reqs; - fcp->num_itns = cfg->fwcfg.num_rports; - fcp->bfa = bfa; - - /* - * Setup the pool of snsbase addr's, that is passed to fw as - * part of bfi_iocfc_cfg_s. - */ - num_io_req = (cfg->fwcfg.num_ioim_reqs + cfg->fwcfg.num_fwtio_reqs); - nsegs = BFI_MEM_DMA_NSEGS(num_io_req, BFI_IOIM_SNSLEN); - - bfa_mem_dma_seg_iter(fcp, seg_ptr, nsegs, idx) { - - if (!bfa_mem_dma_virt(seg_ptr)) - break; - - fcp->snsbase[idx].pa = bfa_mem_dma_phys(seg_ptr); - fcp->snsbase[idx].kva = bfa_mem_dma_virt(seg_ptr); - bfa_iocfc_set_snsbase(bfa, idx, fcp->snsbase[idx].pa); - } - - bfa_fcpim_attach(fcp, bfad, cfg, pcidev); - - bfa_iotag_attach(fcp); - - fcp->itn_arr = (struct bfa_itn_s *) bfa_mem_kva_curp(fcp); - bfa_mem_kva_curp(fcp) = (u8 *)fcp->itn_arr + - (fcp->num_itns * sizeof(struct bfa_itn_s)); - memset(fcp->itn_arr, 0, - (fcp->num_itns * sizeof(struct bfa_itn_s))); -} - -static void -bfa_fcp_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcp_start(struct bfa_s *bfa) -{ -} - -static void -bfa_fcp_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_fcp_iocdisable(struct bfa_s *bfa) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - - /* Enqueue unused ioim resources to free_q */ - list_splice_tail_init(&fcp->iotag_unused_q, &fcp->iotag_ioim_free_q); - - bfa_fcpim_iocdisable(fcp); -} - -void -bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw) -{ - struct bfa_fcp_mod_s *mod = BFA_FCP_MOD(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (mod->num_ioim_reqs - num_ioim_fw); i++) { - bfa_q_deq_tail(&mod->iotag_ioim_free_q, &qe); - list_add_tail(qe, &mod->iotag_unused_q); - } -} - -void -bfa_itn_create(struct bfa_s *bfa, struct bfa_rport_s *rport, - void (*isr)(struct bfa_s *bfa, struct bfi_msg_s *m)) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - struct bfa_itn_s *itn; - - itn = BFA_ITN_FROM_TAG(fcp, rport->rport_tag); - itn->isr = isr; -} - -/* - * Itn interrupt processing. - */ -void -bfa_itn_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - union bfi_itn_i2h_msg_u msg; - struct bfa_itn_s *itn; - - msg.msg = m; - itn = BFA_ITN_FROM_TAG(fcp, msg.create_rsp->bfa_handle); - - if (itn->isr) - itn->isr(bfa, m); - else - WARN_ON(1); -} - -void -bfa_iotag_attach(struct bfa_fcp_mod_s *fcp) -{ - struct bfa_iotag_s *iotag; - u16 num_io_req, i; - - iotag = (struct bfa_iotag_s *) bfa_mem_kva_curp(fcp); - fcp->iotag_arr = iotag; - - INIT_LIST_HEAD(&fcp->iotag_ioim_free_q); - INIT_LIST_HEAD(&fcp->iotag_tio_free_q); - INIT_LIST_HEAD(&fcp->iotag_unused_q); - - num_io_req = fcp->num_ioim_reqs + fcp->num_fwtio_reqs; - for (i = 0; i < num_io_req; i++, iotag++) { - memset(iotag, 0, sizeof(struct bfa_iotag_s)); - iotag->tag = i; - if (i < fcp->num_ioim_reqs) - list_add_tail(&iotag->qe, &fcp->iotag_ioim_free_q); - else - list_add_tail(&iotag->qe, &fcp->iotag_tio_free_q); - } - - bfa_mem_kva_curp(fcp) = (u8 *) iotag; -} diff --git a/trunk/drivers/scsi/bfa/bfa_fcpim.h b/trunk/drivers/scsi/bfa/bfa_fcpim.h index 57b695ad4ee5..1e38dade8423 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcpim.h +++ b/trunk/drivers/scsi/bfa/bfa_fcpim.h @@ -24,34 +24,6 @@ #include "bfa_defs_svc.h" #include "bfa_cs.h" -/* FCP module related definitions */ -#define BFA_IO_MAX BFI_IO_MAX -#define BFA_FWTIO_MAX 2000 - -struct bfa_fcp_mod_s; -struct bfa_iotag_s { - struct list_head qe; /* queue element */ - u16 tag; /* FW IO tag */ -}; - -struct bfa_itn_s { - bfa_isr_func_t isr; -}; - -void bfa_itn_create(struct bfa_s *bfa, struct bfa_rport_s *rport, - void (*isr)(struct bfa_s *bfa, struct bfi_msg_s *m)); -void bfa_itn_isr(struct bfa_s *bfa, struct bfi_msg_s *m); -void bfa_iotag_attach(struct bfa_fcp_mod_s *fcp); -void bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw); - -#define BFA_FCP_MOD(_hal) (&(_hal)->modules.fcp_mod) -#define BFA_MEM_FCP_KVA(__bfa) (&(BFA_FCP_MOD(__bfa)->kva_seg)) -#define BFA_IOTAG_FROM_TAG(_fcp, _tag) \ - (&(_fcp)->iotag_arr[(_tag & BFA_IOIM_IOTAG_MASK)]) -#define BFA_ITN_FROM_TAG(_fcp, _tag) \ - ((_fcp)->itn_arr + ((_tag) & ((_fcp)->num_itns - 1))) -#define BFA_SNSINFO_FROM_TAG(_fcp, _tag) \ - bfa_mem_get_dmabuf_kva(_fcp, _tag, BFI_IOIM_SNSLEN) #define BFA_ITNIM_MIN 32 #define BFA_ITNIM_MAX 1024 @@ -103,24 +75,25 @@ struct bfad_tskim_s; typedef void (*bfa_fcpim_profile_t) (struct bfa_ioim_s *ioim); -struct bfa_fcpim_s { +struct bfa_fcpim_mod_s { struct bfa_s *bfa; - struct bfa_fcp_mod_s *fcp; struct bfa_itnim_s *itnim_arr; struct bfa_ioim_s *ioim_arr; struct bfa_ioim_sp_s *ioim_sp_arr; struct bfa_tskim_s *tskim_arr; + struct bfa_dma_s snsbase; int num_itnims; + int num_ioim_reqs; int num_tskim_reqs; u32 path_tov; u16 q_depth; u8 reqq; /* Request queue to be used */ u8 rsvd; struct list_head itnim_q; /* queue of active itnim */ + struct list_head ioim_free_q; /* free IO resources */ struct list_head ioim_resfree_q; /* IOs waiting for f/w */ struct list_head ioim_comp_q; /* IO global comp Q */ struct list_head tskim_free_q; - struct list_head tskim_unused_q; /* Unused tskim Q */ u32 ios_active; /* current active IOs */ u32 delay_comp; struct bfa_fcpim_del_itn_stats_s del_itn_stats; @@ -131,25 +104,6 @@ struct bfa_fcpim_s { bfa_fcpim_profile_t profile_start; }; -/* Max FCP dma segs required */ -#define BFA_FCP_DMA_SEGS BFI_IOIM_SNSBUF_SEGS - -struct bfa_fcp_mod_s { - struct bfa_s *bfa; - struct list_head iotag_ioim_free_q; /* free IO resources */ - struct list_head iotag_tio_free_q; /* free IO resources */ - struct list_head iotag_unused_q; /* unused IO resources*/ - struct bfa_iotag_s *iotag_arr; - struct bfa_itn_s *itn_arr; - int num_ioim_reqs; - int num_fwtio_reqs; - int num_itns; - struct bfa_dma_s snsbase[BFA_FCP_DMA_SEGS]; - struct bfa_fcpim_s fcpim; - struct bfa_mem_dma_s dma_seg[BFA_FCP_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; -}; - /* * BFA IO (initiator mode) */ @@ -157,7 +111,7 @@ struct bfa_ioim_s { struct list_head qe; /* queue elememt */ bfa_sm_t sm; /* BFA ioim state machine */ struct bfa_s *bfa; /* BFA module */ - struct bfa_fcpim_s *fcpim; /* parent fcpim module */ + struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */ struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ struct bfad_ioim_s *dio; /* driver IO handle */ u16 iotag; /* FWI IO tag */ @@ -175,6 +129,7 @@ struct bfa_ioim_s { struct bfa_ioim_sp_s { struct bfi_msg_s comp_rspmsg; /* IO comp f/w response */ + u8 *snsinfo; /* sense info for this IO */ struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ bfa_boolean_t abort_explicit; /* aborted by OS */ @@ -188,7 +143,7 @@ struct bfa_tskim_s { struct list_head qe; bfa_sm_t sm; struct bfa_s *bfa; /* BFA module */ - struct bfa_fcpim_s *fcpim; /* parent fcpim module */ + struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */ struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */ bfa_boolean_t notify; /* notify itnim on TM comp */ @@ -227,13 +182,13 @@ struct bfa_itnim_s { struct bfa_wc_s wc; /* waiting counter */ struct bfa_timer_s timer; /* pending IO TOV */ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - struct bfa_fcpim_s *fcpim; /* fcpim module */ + struct bfa_fcpim_mod_s *fcpim; /* fcpim module */ struct bfa_itnim_iostats_s stats; struct bfa_itnim_ioprofile_s ioprofile; }; #define bfa_itnim_is_online(_itnim) ((_itnim)->is_online) -#define BFA_FCPIM(_hal) (&(_hal)->modules.fcp_mod.fcpim) +#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod) #define BFA_IOIM_TAG_2_ID(_iotag) ((_iotag) & BFA_IOIM_IOTAG_MASK) #define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \ (&fcpim->ioim_arr[(_iotag & BFA_IOIM_IOTAG_MASK)]) @@ -241,9 +196,9 @@ struct bfa_itnim_s { (&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)]) #define bfa_io_profile_start_time(_bfa) \ - ((_bfa)->modules.fcp_mod.fcpim.io_profile_start_time) + (_bfa->modules.fcpim_mod.io_profile_start_time) #define bfa_fcpim_get_io_profile(_bfa) \ - ((_bfa)->modules.fcp_mod.fcpim.io_profile) + (_bfa->modules.fcpim_mod.io_profile) #define bfa_ioim_update_iotag(__ioim) do { \ uint16_t k = (__ioim)->iotag >> BFA_IOIM_RETRY_TAG_OFFSET; \ k++; (__ioim)->iotag &= BFA_IOIM_IOTAG_MASK; \ @@ -262,7 +217,8 @@ bfa_ioim_maxretry_reached(struct bfa_ioim_s *ioim) /* * function prototypes */ -void bfa_ioim_attach(struct bfa_fcpim_s *fcpim); +void bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, + struct bfa_meminfo_s *minfo); void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); void bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); @@ -272,15 +228,18 @@ void bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, void bfa_ioim_iocdisable(struct bfa_ioim_s *ioim); void bfa_ioim_tov(struct bfa_ioim_s *ioim); -void bfa_tskim_attach(struct bfa_fcpim_s *fcpim); +void bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, + struct bfa_meminfo_s *minfo); void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); void bfa_tskim_iodone(struct bfa_tskim_s *tskim); void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim); void bfa_tskim_cleanup(struct bfa_tskim_s *tskim); -void bfa_tskim_res_recfg(struct bfa_s *bfa, u16 num_tskim_fw); -void bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len); -void bfa_itnim_attach(struct bfa_fcpim_s *fcpim); +void bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len); +void bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, + struct bfa_meminfo_s *minfo); +void bfa_itnim_detach(struct bfa_fcpim_mod_s *fcpim); void bfa_itnim_iocdisable(struct bfa_itnim_s *itnim); void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); void bfa_itnim_iodone(struct bfa_itnim_s *itnim); @@ -293,17 +252,13 @@ bfa_boolean_t bfa_itnim_hold_io(struct bfa_itnim_s *itnim); void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov); u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa); u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa); -bfa_status_t bfa_fcpim_port_iostats(struct bfa_s *bfa, - struct bfa_itnim_iostats_s *stats, u8 lp_tag); -void bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *fcpim_stats, - struct bfa_itnim_iostats_s *itnim_stats); #define bfa_fcpim_ioredirect_enabled(__bfa) \ - (((struct bfa_fcpim_s *)(BFA_FCPIM(__bfa)))->ioredirect) + (((struct bfa_fcpim_mod_s *)(BFA_FCPIM_MOD(__bfa)))->ioredirect) #define bfa_fcpim_get_next_reqq(__bfa, __qid) \ { \ - struct bfa_fcpim_s *__fcpim = BFA_FCPIM(__bfa); \ + struct bfa_fcpim_mod_s *__fcpim = BFA_FCPIM_MOD(__bfa); \ __fcpim->reqq++; \ __fcpim->reqq &= (BFI_IOC_MAX_CQS - 1); \ *(__qid) = __fcpim->reqq; \ diff --git a/trunk/drivers/scsi/bfa/bfa_fcs.c b/trunk/drivers/scsi/bfa/bfa_fcs.c index a9b22bc48bc3..9b43ca4b6778 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs.c +++ b/trunk/drivers/scsi/bfa/bfa_fcs.c @@ -92,49 +92,25 @@ bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, void bfa_fcs_init(struct bfa_fcs_s *fcs) { - int i; + int i, npbc_vports; struct bfa_fcs_mod_s *mod; + struct bfi_pbc_vport_s pbc_vports[BFI_PBC_MAX_VPORTS]; for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) { mod = &fcs_modules[i]; if (mod->modinit) mod->modinit(fcs); } -} - -/* - * FCS update cfg - reset the pwwn/nwwn of fabric base logical port - * with values learned during bfa_init firmware GETATTR REQ. - */ -void -bfa_fcs_update_cfg(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric = &fcs->fabric; - struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg; - struct bfa_ioc_s *ioc = &fabric->fcs->bfa->ioc; - - port_cfg->nwwn = ioc->attr->nwwn; - port_cfg->pwwn = ioc->attr->pwwn; -} - -/* - * fcs pbc vport initialization - */ -void -bfa_fcs_pbc_vport_init(struct bfa_fcs_s *fcs) -{ - int i, npbc_vports; - struct bfi_pbc_vport_s pbc_vports[BFI_PBC_MAX_VPORTS]; - /* Initialize pbc vports */ if (!fcs->min_cfg) { npbc_vports = - bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_vports); + bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_vports); for (i = 0; i < npbc_vports; i++) bfa_fcb_pbc_vport_create(fcs->bfa->bfad, pbc_vports[i]); } } + /* * brief * FCS driver details initialization. @@ -192,14 +168,11 @@ bfa_fcs_exit(struct bfa_fcs_s *fcs) #define BFA_FCS_FABRIC_CLEANUP_DELAY (10000) /* Milliseconds */ #define bfa_fcs_fabric_set_opertype(__fabric) do { \ - if (bfa_fcport_get_topology((__fabric)->fcs->bfa) \ - == BFA_PORT_TOPOLOGY_P2P) { \ - if (fabric->fab_type == BFA_FCS_FABRIC_SWITCHED) \ + if (bfa_fcport_get_topology((__fabric)->fcs->bfa) \ + == BFA_PORT_TOPOLOGY_P2P) \ (__fabric)->oper_type = BFA_PORT_TYPE_NPORT; \ else \ - (__fabric)->oper_type = BFA_PORT_TYPE_P2P; \ - } else \ - (__fabric)->oper_type = BFA_PORT_TYPE_NLPORT; \ + (__fabric)->oper_type = BFA_PORT_TYPE_NLPORT; \ } while (0) /* @@ -223,9 +196,6 @@ static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg, u32 rsp_len, u32 resid_len, struct fchs_s *rspfchs); -static u8 bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric); -static bfa_boolean_t bfa_fcs_fabric_is_bbscn_enabled( - struct bfa_fcs_fabric_s *fabric); static void bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric, enum bfa_fcs_fabric_event event); @@ -299,8 +269,8 @@ bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, break; case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); + bfa_wc_down(&fabric->fcs->wc); break; default: @@ -352,8 +322,7 @@ bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, case BFA_FCS_FABRIC_SM_CONT_OP: bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, - fabric->bb_credit, - bfa_fcs_fabric_oper_bbscn(fabric)); + fabric->bb_credit); fabric->fab_type = BFA_FCS_FABRIC_SWITCHED; if (fabric->auth_reqd && fabric->is_auth) { @@ -381,8 +350,7 @@ bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, case BFA_FCS_FABRIC_SM_NO_FABRIC: fabric->fab_type = BFA_FCS_FABRIC_N2N; bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, - fabric->bb_credit, - bfa_fcs_fabric_oper_bbscn(fabric)); + fabric->bb_credit); bfa_fcs_fabric_notify_online(fabric); bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric); break; @@ -550,11 +518,7 @@ bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric, case BFA_FCS_FABRIC_SM_NO_FABRIC: bfa_trc(fabric->fcs, fabric->bb_credit); bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, - fabric->bb_credit, - bfa_fcs_fabric_oper_bbscn(fabric)); - break; - - case BFA_FCS_FABRIC_SM_RETRY_OP: + fabric->bb_credit); break; default: @@ -800,10 +764,6 @@ bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status) case BFA_STATUS_FABRIC_RJT: fabric->stats.flogi_rejects++; - if (fabric->lps->lsrjt_rsn == FC_LS_RJT_RSN_LOGICAL_ERROR && - fabric->lps->lsrjt_expl == FC_LS_RJT_EXP_NO_ADDL_INFO) - fabric->fcs->bbscn_flogi_rjt = BFA_TRUE; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); return; @@ -833,7 +793,6 @@ bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status) */ fabric->bport.port_topo.pn2n.rem_port_wwn = fabric->lps->pr_pwwn; - fabric->fab_type = BFA_FCS_FABRIC_N2N; bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC); } @@ -849,17 +808,13 @@ bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric) { struct bfa_s *bfa = fabric->fcs->bfa; struct bfa_lport_cfg_s *pcfg = &fabric->bport.port_cfg; - u8 alpa = 0, bb_scn = 0; + u8 alpa = 0; if (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP) alpa = bfa_fcport_get_myalpa(bfa); - if (bfa_fcs_fabric_is_bbscn_enabled(fabric) && - (!fabric->fcs->bbscn_flogi_rjt)) - bb_scn = BFA_FCS_PORT_DEF_BB_SCN; - bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_fcport_get_maxfrsize(bfa), - pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd, bb_scn); + pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd); fabric->stats.flogi_sent++; } @@ -917,40 +872,6 @@ bfa_fcs_fabric_delay(void *cbarg) bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED); } -/* - * Computes operating BB_SCN value - */ -static u8 -bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric) -{ - u8 pr_bbscn = fabric->lps->pr_bbscn; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fabric->fcs->bfa); - - if (!(fcport->cfg.bb_scn_state && pr_bbscn)) - return 0; - - /* return max of local/remote bb_scn values */ - return ((pr_bbscn > BFA_FCS_PORT_DEF_BB_SCN) ? - pr_bbscn : BFA_FCS_PORT_DEF_BB_SCN); -} - -/* - * Check if BB_SCN can be enabled. - */ -static bfa_boolean_t -bfa_fcs_fabric_is_bbscn_enabled(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fabric->fcs->bfa); - - if (bfa_ioc_get_fcmode(&fabric->fcs->bfa->ioc) && - fcport->cfg.bb_scn_state && - !bfa_fcport_is_qos_enabled(fabric->fcs->bfa) && - !bfa_fcport_is_trunk_enabled(fabric->fcs->bfa)) - return BFA_TRUE; - else - return BFA_FALSE; -} - /* * Delete all vports and wait for vport delete completions. */ @@ -1068,7 +989,6 @@ void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric) { bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - fabric->fcs->bbscn_flogi_rjt = BFA_FALSE; bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN); } @@ -1272,7 +1192,6 @@ bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, } fabric->bb_credit = be16_to_cpu(flogi->csp.bbcred); - fabric->lps->pr_bbscn = (be16_to_cpu(flogi->csp.rxsz) >> 12); bport->port_topo.pn2n.rem_port_wwn = flogi->port_name; bport->port_topo.pn2n.reply_oxid = fchs->ox_id; @@ -1305,10 +1224,9 @@ bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric) n2n_port->reply_oxid, pcfg->pwwn, pcfg->nwwn, bfa_fcport_get_maxfrsize(bfa), - bfa_fcport_get_rx_bbcredit(bfa), - bfa_fcs_fabric_oper_bbscn(fabric)); + bfa_fcport_get_rx_bbcredit(bfa)); - bfa_fcxp_send(fcxp, NULL, fabric->vf_id, fabric->lps->bfa_tag, + bfa_fcxp_send(fcxp, NULL, fabric->vf_id, fabric->lps->lp_tag, BFA_FALSE, FC_CLASS_3, reqlen, &fchs, bfa_fcs_fabric_flogiacc_comp, fabric, FC_MAX_PDUSZ, 0); @@ -1379,45 +1297,6 @@ bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id) return NULL; } -/* - * Return the list of local logical ports present in the given VF. - * - * @param[in] vf vf for which logical ports are returned - * @param[out] lpwwn returned logical port wwn list - * @param[in,out] nlports in:size of lpwwn list; - * out:total elements present, - * actual elements returned is limited by the size - */ -void -bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports) -{ - struct list_head *qe; - struct bfa_fcs_vport_s *vport; - int i = 0; - struct bfa_fcs_s *fcs; - - if (vf == NULL || lpwwn == NULL || *nlports == 0) - return; - - fcs = vf->fcs; - - bfa_trc(fcs, vf->vf_id); - bfa_trc(fcs, (uint32_t) *nlports); - - lpwwn[i++] = vf->bport.port_cfg.pwwn; - - list_for_each(qe, &vf->vport_q) { - if (i >= *nlports) - break; - - vport = (struct bfa_fcs_vport_s *) qe; - lpwwn[i++] = vport->lport.port_cfg.pwwn; - } - - bfa_trc(fcs, i); - *nlports = i; -} - /* * BFA FCS PPORT ( physical port) */ diff --git a/trunk/drivers/scsi/bfa/bfa_fcs.h b/trunk/drivers/scsi/bfa/bfa_fcs.h index a5f1faf335a7..61cdce4bd913 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs.h +++ b/trunk/drivers/scsi/bfa/bfa_fcs.h @@ -254,9 +254,6 @@ struct bfa_fcs_fabric_s; #define BFA_FCS_PORT_SYMBNAME_OSINFO_SZ 48 #define BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ 16 -/* bb_scn value in 2^bb_scn */ -#define BFA_FCS_PORT_DEF_BB_SCN 3 - /* * Get FC port ID for a logical port. */ @@ -382,7 +379,6 @@ void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport); -void bfa_fcs_vport_stop_comp(struct bfa_fcs_vport_s *vport); #define BFA_FCS_RPORT_DEF_DEL_TIMEOUT 90 /* in secs */ #define BFA_FCS_RPORT_MAX_RETRIES (5) @@ -424,7 +420,6 @@ struct bfa_fcs_rport_s { enum fc_cos fc_cos; /* FC classes of service supp */ bfa_boolean_t cisc; /* CISC capable device */ bfa_boolean_t prlo; /* processing prlo or LOGO */ - bfa_boolean_t plogi_pending; /* Rx Plogi Pending */ wwn_t pwwn; /* port wwn of rport */ wwn_t nwwn; /* node wwn of rport */ struct bfa_rport_symname_s psym_name; /* port symbolic name */ @@ -452,8 +447,6 @@ bfa_fcs_rport_get_halrport(struct bfa_fcs_rport_s *rport) /* * bfa fcs rport API functions */ -void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, - struct bfa_rport_attr_s *attr); struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn); struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn( @@ -598,21 +591,10 @@ void bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim); void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs, u16 len); -#define BFA_FCS_FDMI_SUPP_SPEEDS_4G (FDMI_TRANS_SPEED_1G | \ - FDMI_TRANS_SPEED_2G | \ - FDMI_TRANS_SPEED_4G) - -#define BFA_FCS_FDMI_SUPP_SPEEDS_8G (FDMI_TRANS_SPEED_1G | \ - FDMI_TRANS_SPEED_2G | \ - FDMI_TRANS_SPEED_4G | \ - FDMI_TRANS_SPEED_8G) - -#define BFA_FCS_FDMI_SUPP_SPEEDS_16G (FDMI_TRANS_SPEED_2G | \ - FDMI_TRANS_SPEED_4G | \ - FDMI_TRANS_SPEED_8G | \ - FDMI_TRANS_SPEED_16G) - -#define BFA_FCS_FDMI_SUPP_SPEEDS_10G FDMI_TRANS_SPEED_10G +#define BFA_FCS_FDMI_SUPORTED_SPEEDS (FDMI_TRANS_SPEED_1G | \ + FDMI_TRANS_SPEED_2G | \ + FDMI_TRANS_SPEED_4G | \ + FDMI_TRANS_SPEED_8G) /* * HBA Attribute Block : BFA internal representation. Note : Some variable @@ -667,8 +649,6 @@ struct bfa_fcs_s { struct bfa_trc_mod_s *trcmod; /* tracing module */ bfa_boolean_t vf_enabled; /* VF mode is enabled */ bfa_boolean_t fdmi_enabled; /* FDMI is enabled */ - bfa_boolean_t bbscn_enabled; /* Driver Config Parameter */ - bfa_boolean_t bbscn_flogi_rjt;/* FLOGI reject due to BB_SCN */ bfa_boolean_t min_cfg; /* min cfg enabled/disabled */ u16 port_vfid; /* port default VF ID */ struct bfa_fcs_driver_info_s driver_info; @@ -735,8 +715,6 @@ void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, bfa_boolean_t min_cfg); void bfa_fcs_init(struct bfa_fcs_s *fcs); -void bfa_fcs_pbc_vport_init(struct bfa_fcs_s *fcs); -void bfa_fcs_update_cfg(struct bfa_fcs_s *fcs); void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, struct bfa_fcs_driver_info_s *driver_info); void bfa_fcs_exit(struct bfa_fcs_s *fcs); @@ -745,7 +723,6 @@ void bfa_fcs_exit(struct bfa_fcs_s *fcs); * bfa fcs vf public functions */ bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id); -void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports); /* * fabric protected interface functions diff --git a/trunk/drivers/scsi/bfa/bfa_fcs_fcpim.c b/trunk/drivers/scsi/bfa/bfa_fcs_fcpim.c index 29b4108be269..e7b49f4cb51f 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs_fcpim.c +++ b/trunk/drivers/scsi/bfa/bfa_fcs_fcpim.c @@ -54,7 +54,6 @@ enum bfa_fcs_itnim_event { BFA_FCS_ITNIM_SM_INITIATOR = 9, /* rport is initiator */ BFA_FCS_ITNIM_SM_DELETE = 10, /* delete event from rport */ BFA_FCS_ITNIM_SM_PRLO = 11, /* delete event from rport */ - BFA_FCS_ITNIM_SM_RSP_NOT_SUPP = 12, /* cmd not supported rsp */ }; static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, @@ -179,10 +178,6 @@ bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, BFA_FCS_RETRY_TIMEOUT); break; - case BFA_FCS_ITNIM_SM_RSP_NOT_SUPP: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - break; - case BFA_FCS_ITNIM_SM_OFFLINE: bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); bfa_fcxp_discard(itnim->fcxp); @@ -452,7 +447,6 @@ bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, itnim->rport->scsi_function = BFA_RPORT_INITIATOR; itnim->stats.prli_rsp_acc++; - itnim->stats.initiator++; bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK); return; @@ -478,10 +472,6 @@ bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, bfa_trc(itnim->fcs, ls_rjt->reason_code_expl); itnim->stats.prli_rsp_rjt++; - if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) { - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_NOT_SUPP); - return; - } bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR); } } diff --git a/trunk/drivers/scsi/bfa/bfa_fcs_lport.c b/trunk/drivers/scsi/bfa/bfa_fcs_lport.c index f8251a91ba91..1d6be8c14473 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/trunk/drivers/scsi/bfa/bfa_fcs_lport.c @@ -74,7 +74,6 @@ enum bfa_fcs_lport_event { BFA_FCS_PORT_SM_OFFLINE = 3, BFA_FCS_PORT_SM_DELETE = 4, BFA_FCS_PORT_SM_DELRPORT = 5, - BFA_FCS_PORT_SM_STOP = 6, }; static void bfa_fcs_lport_sm_uninit(struct bfa_fcs_lport_s *port, @@ -87,8 +86,6 @@ static void bfa_fcs_lport_sm_offline(struct bfa_fcs_lport_s *port, enum bfa_fcs_lport_event event); static void bfa_fcs_lport_sm_deleting(struct bfa_fcs_lport_s *port, enum bfa_fcs_lport_event event); -static void bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event); static void bfa_fcs_lport_sm_uninit( @@ -126,12 +123,6 @@ bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port, bfa_fcs_lport_deleted(port); break; - case BFA_FCS_PORT_SM_STOP: - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - break; - case BFA_FCS_PORT_SM_OFFLINE: break; @@ -157,23 +148,6 @@ bfa_fcs_lport_sm_online( bfa_fcs_lport_offline_actions(port); break; - case BFA_FCS_PORT_SM_STOP: - __port_action[port->fabric->fab_type].offline(port); - - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_init); - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - } else { - bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping); - list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - bfa_sm_send_event(rport, RPSM_EVENT_DELETE); - } - } - break; - case BFA_FCS_PORT_SM_DELETE: __port_action[port->fabric->fab_type].offline(port); @@ -215,21 +189,6 @@ bfa_fcs_lport_sm_offline( bfa_fcs_lport_online_actions(port); break; - case BFA_FCS_PORT_SM_STOP: - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_init); - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - } else { - bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping); - list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - bfa_sm_send_event(rport, RPSM_EVENT_DELETE); - } - } - break; - case BFA_FCS_PORT_SM_DELETE: if (port->num_rports == 0) { bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit); @@ -252,28 +211,6 @@ bfa_fcs_lport_sm_offline( } } -static void -bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event) -{ - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case BFA_FCS_PORT_SM_DELRPORT: - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_init); - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - } - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - static void bfa_fcs_lport_sm_deleting( struct bfa_fcs_lport_s *port, @@ -327,40 +264,6 @@ bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, FC_MAX_PDUSZ, 0); } -/* - * Send a FCCT Reject - */ -static void -bfa_fcs_lport_send_fcgs_rjt(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs, u8 reason_code, u8 reason_code_expl) -{ - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - struct bfa_rport_s *bfa_rport = NULL; - int len; - struct ct_hdr_s *rx_cthdr = (struct ct_hdr_s *)(rx_fchs + 1); - struct ct_hdr_s *ct_hdr; - - bfa_trc(port->fcs, rx_fchs->d_id); - bfa_trc(port->fcs, rx_fchs->s_id); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - ct_hdr = bfa_fcxp_get_reqbuf(fcxp); - ct_hdr->gs_type = rx_cthdr->gs_type; - ct_hdr->gs_sub_type = rx_cthdr->gs_sub_type; - - len = fc_gs_rjt_build(&fchs, ct_hdr, rx_fchs->s_id, - bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id, reason_code, reason_code_expl); - - bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); -} - /* * Process incoming plogi from a remote port. */ @@ -744,16 +647,6 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport, bfa_fcs_lport_abts_acc(lport, fchs); return; } - - if (fchs->type == FC_TYPE_SERVICES) { - /* - * Unhandled FC-GS frames. Send a FC-CT Reject - */ - bfa_fcs_lport_send_fcgs_rjt(lport, fchs, CT_RSN_NOT_SUPP, - CT_NS_EXP_NOADDITIONAL); - return; - } - /* * look for a matching remote port ID */ @@ -942,8 +835,8 @@ bfa_fcs_lport_attach(struct bfa_fcs_lport_s *lport, struct bfa_fcs_s *fcs, lport->fcs = fcs; lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id); lport->vport = vport; - lport->lp_tag = (vport) ? vport->lps->bfa_tag : - lport->fabric->lps->bfa_tag; + lport->lp_tag = (vport) ? vport->lps->lp_tag : + lport->fabric->lps->lp_tag; INIT_LIST_HEAD(&lport->rport_q); lport->num_rports = 0; @@ -1181,8 +1074,6 @@ static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi, struct bfa_fcs_fdmi_hba_attr_s *hba_attr); static void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, struct bfa_fcs_fdmi_port_attr_s *port_attr); -u32 bfa_fcs_fdmi_convert_speed(enum bfa_port_speed pport_speed); - /* * fcs_fdmi_sm FCS FDMI state machine */ @@ -1781,7 +1672,7 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld) memcpy(attr->value, fcs_hba_attr->driver_version, templen); templen = fc_roundup(templen, sizeof(u32)); curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; + len += templen;; count++; attr->len = cpu_to_be16(templen + sizeof(attr->type) + sizeof(templen)); @@ -2269,36 +2160,12 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, /* * Supported Speeds */ - switch (pport_attr.speed_supported) { - case BFA_PORT_SPEED_16GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_16G); - break; - - case BFA_PORT_SPEED_10GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_10G); - break; - - case BFA_PORT_SPEED_8GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_8G); - break; - - case BFA_PORT_SPEED_4GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_4G); - break; - - default: - bfa_sm_fault(port->fcs, pport_attr.speed_supported); - } + port_attr->supp_speed = cpu_to_be32(BFA_FCS_FDMI_SUPORTED_SPEEDS); /* * Current Speed */ - port_attr->curr_speed = cpu_to_be32( - bfa_fcs_fdmi_convert_speed(pport_attr.speed)); + port_attr->curr_speed = cpu_to_be32(pport_attr.speed); /* * Max PDU Size. @@ -2319,41 +2186,6 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, } -/* - * Convert BFA speed to FDMI format. - */ -u32 -bfa_fcs_fdmi_convert_speed(bfa_port_speed_t pport_speed) -{ - u32 ret; - - switch (pport_speed) { - case BFA_PORT_SPEED_1GBPS: - case BFA_PORT_SPEED_2GBPS: - ret = pport_speed; - break; - - case BFA_PORT_SPEED_4GBPS: - ret = FDMI_TRANS_SPEED_4G; - break; - - case BFA_PORT_SPEED_8GBPS: - ret = FDMI_TRANS_SPEED_8G; - break; - - case BFA_PORT_SPEED_10GBPS: - ret = FDMI_TRANS_SPEED_10G; - break; - - case BFA_PORT_SPEED_16GBPS: - ret = FDMI_TRANS_SPEED_16G; - break; - - default: - ret = FDMI_TRANS_SPEED_UNKNOWN; - } - return ret; -} void bfa_fcs_lport_fdmi_init(struct bfa_fcs_lport_ms_s *ms) @@ -2997,8 +2829,7 @@ bfa_fcs_lport_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_hton3b(FC_MGMT_SERVER), bfa_fcs_lport_get_fcid(port), 0, port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); + bfa_fcport_get_maxfrsize(port->fcs->bfa)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, @@ -3742,7 +3573,7 @@ bfa_fcs_lport_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_trc(port->fcs, port->pid); - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) { port->stats.ns_plogi_alloc_wait++; bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, @@ -3755,8 +3586,7 @@ bfa_fcs_lport_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_hton3b(FC_NAME_SERVER), bfa_fcs_lport_get_fcid(port), 0, port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); + bfa_fcport_get_maxfrsize(port->fcs->bfa)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, @@ -4932,8 +4762,8 @@ bfa_fcs_lport_get_rport_max_speed(bfa_fcs_lport_t *port) while (qe != qh) { rport = (struct bfa_fcs_rport_s *) qe; if ((bfa_ntoh3b(rport->pid) > 0xFFF000) || - (bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE) || - (rport->scsi_function != BFA_RPORT_TARGET)) { + (bfa_fcs_rport_get_state(rport) == + BFA_RPORT_OFFLINE)) { qe = bfa_q_next(qe); continue; } @@ -4946,15 +4776,17 @@ bfa_fcs_lport_get_rport_max_speed(bfa_fcs_lport_t *port) bfa_fcport_get_ratelim_speed(port->fcs->bfa); } - if (rport_speed > max_speed) + if ((rport_speed == BFA_PORT_SPEED_8GBPS) || + (rport_speed > port_speed)) { max_speed = rport_speed; + break; + } else if (rport_speed > max_speed) { + max_speed = rport_speed; + } qe = bfa_q_next(qe); } - if (max_speed > port_speed) - max_speed = port_speed; - bfa_trc(fcs, max_speed); return max_speed; } @@ -5086,7 +4918,6 @@ enum bfa_fcs_vport_event { BFA_FCS_VPORT_SM_DELCOMP = 11, /* lport delete completion */ BFA_FCS_VPORT_SM_RSP_DUP_WWN = 12, /* Dup wnn error*/ BFA_FCS_VPORT_SM_RSP_FAILED = 13, /* non-retryable failure */ - BFA_FCS_VPORT_SM_STOPCOMP = 14, /* vport delete completion */ }; static void bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, @@ -5099,8 +4930,6 @@ static void bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); static void bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_fdisc_rsp_wait(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); static void bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); static void bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport, @@ -5111,10 +4940,6 @@ static void bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); static void bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_stopping(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); static struct bfa_sm_table_s vport_sm_table[] = { {BFA_SM(bfa_fcs_vport_sm_uninit), BFA_FCS_VPORT_UNINIT}, @@ -5122,7 +4947,6 @@ static struct bfa_sm_table_s vport_sm_table[] = { {BFA_SM(bfa_fcs_vport_sm_offline), BFA_FCS_VPORT_OFFLINE}, {BFA_SM(bfa_fcs_vport_sm_fdisc), BFA_FCS_VPORT_FDISC}, {BFA_SM(bfa_fcs_vport_sm_fdisc_retry), BFA_FCS_VPORT_FDISC_RETRY}, - {BFA_SM(bfa_fcs_vport_sm_fdisc_rsp_wait), BFA_FCS_VPORT_FDISC_RSP_WAIT}, {BFA_SM(bfa_fcs_vport_sm_online), BFA_FCS_VPORT_ONLINE}, {BFA_SM(bfa_fcs_vport_sm_deleting), BFA_FCS_VPORT_DELETING}, {BFA_SM(bfa_fcs_vport_sm_cleanup), BFA_FCS_VPORT_CLEANUP}, @@ -5218,11 +5042,6 @@ bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport, bfa_fcs_vport_do_fdisc(vport); break; - case BFA_FCS_VPORT_SM_STOP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_sm_send_event(&vport->lport, BFA_FCS_PORT_SM_STOP); - break; - case BFA_FCS_VPORT_SM_OFFLINE: /* * This can happen if the vport couldn't be initialzied @@ -5251,7 +5070,9 @@ bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, switch (event) { case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc_rsp_wait); + bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); + bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); + bfa_fcs_lport_delete(&vport->lport); break; case BFA_FCS_VPORT_SM_OFFLINE: @@ -5318,41 +5139,6 @@ bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, } } -/* - * FDISC is in progress and we got a vport delete request - - * this is a wait state while we wait for fdisc response and - * we will transition to the appropriate state - on rsp status. - */ -static void -bfa_fcs_vport_sm_fdisc_rsp_wait(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_RSP_OK: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_deleting); - bfa_fcs_lport_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_DELETE: - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - case BFA_FCS_VPORT_SM_RSP_ERROR: - case BFA_FCS_VPORT_SM_RSP_FAILED: - case BFA_FCS_VPORT_SM_RSP_DUP_WWN: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - bfa_fcs_lport_delete(&vport->lport); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - /* * Vport is online (FDISC is complete). */ @@ -5369,11 +5155,6 @@ bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, bfa_fcs_lport_delete(&vport->lport); break; - case BFA_FCS_VPORT_SM_STOP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_stopping); - bfa_sm_send_event(&vport->lport, BFA_FCS_PORT_SM_STOP); - break; - case BFA_FCS_VPORT_SM_OFFLINE: bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); @@ -5385,32 +5166,6 @@ bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, } } -/* - * Vport is being stopped - awaiting lport stop completion to send - * LOGO to fabric. - */ -static void -bfa_fcs_vport_sm_stopping(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_STOPCOMP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo_for_stop); - bfa_fcs_vport_do_logo(vport); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - /* * Vport is being deleted - awaiting lport delete completion to send * LOGO to fabric. @@ -5481,10 +5236,6 @@ bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, bfa_fcs_vport_free(vport); break; - case BFA_FCS_VPORT_SM_STOPCOMP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_created); - break; - case BFA_FCS_VPORT_SM_DELETE: break; @@ -5493,34 +5244,6 @@ bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, } } -/* - * LOGO is sent to fabric. Vport stop is in progress. Lport stop cleanup - * is done. - */ -static void -bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - /* - * !!! fall through !!! - */ - - case BFA_FCS_VPORT_SM_RSP_OK: - case BFA_FCS_VPORT_SM_RSP_ERROR: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_created); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - /* * LOGO is sent to fabric. Vport delete is in progress. Lport delete cleanup * is done. @@ -5668,10 +5391,7 @@ void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport) { vport->vport_stats.fab_online++; - if (bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); - else - vport->vport_stats.fab_no_npiv++; + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); } /* @@ -5701,15 +5421,6 @@ bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport) bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE); } -/* - * Stop completion callback from associated lport - */ -void -bfa_fcs_vport_stop_comp(struct bfa_fcs_vport_s *vport) -{ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOPCOMP); -} - /* * Delete completion callback from associated lport */ diff --git a/trunk/drivers/scsi/bfa/bfa_fcs_rport.c b/trunk/drivers/scsi/bfa/bfa_fcs_rport.c index 2c514458a6b4..caaee6f06937 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs_rport.c +++ b/trunk/drivers/scsi/bfa/bfa_fcs_rport.c @@ -262,7 +262,6 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_PLOGI_RCVD: - case RPSM_EVENT_PLOGI_COMP: case RPSM_EVENT_SCN: /* * Ignore, SCN is possibly online notification. @@ -471,7 +470,6 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_PLOGI_COMP: break; case RPSM_EVENT_LOGO_RCVD: @@ -486,9 +484,9 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_PLOGI_RCVD: - rport->plogi_pending = BFA_TRUE; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline); + bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE); + bfa_fcs_rport_send_plogiacc(rport, NULL); break; case RPSM_EVENT_DELETE: @@ -893,18 +891,6 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, switch (event) { case RPSM_EVENT_HCB_OFFLINE: - if (bfa_fcs_lport_is_online(rport->port) && - (rport->plogi_pending)) { - rport->plogi_pending = BFA_FALSE; - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_plogiacc_sending); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - } - /* - * !! fall through !! - */ - case RPSM_EVENT_ADDRESS_CHANGE: if (bfa_fcs_lport_is_online(rport->port)) { if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { @@ -935,8 +921,6 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_SCN: case RPSM_EVENT_LOGO_RCVD: case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_PLOGI_RCVD: - case RPSM_EVENT_LOGO_IMP: /* * Ignore, already offline. */ @@ -973,18 +957,10 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, */ if (bfa_fcs_lport_is_online(rport->port) && (!BFA_FCS_PID_IS_WKA(rport->pid))) { - if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsdisc_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - } else { - /* For N2N Direct Attach, try to re-login */ - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_plogi_sending); - rport->plogi_retries = 0; - bfa_fcs_rport_send_plogi(rport, NULL); - } + bfa_sm_set_state(rport, + bfa_fcs_rport_sm_nsdisc_sending); + rport->ns_retries = 0; + bfa_fcs_rport_send_nsdisc(rport, NULL); } else { /* * if it is not a well known address, reset the @@ -1380,8 +1356,7 @@ bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, bfa_fcs_lport_get_fcid(port), 0, port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); + bfa_fcport_get_maxfrsize(port->fcs->bfa)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response, @@ -1501,8 +1476,7 @@ bfa_fcs_rport_send_plogiacc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) rport->pid, bfa_fcs_lport_get_fcid(port), rport->reply_oxid, port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); + bfa_fcport_get_maxfrsize(port->fcs->bfa)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); @@ -2050,11 +2024,6 @@ bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport) rport->stats.onlines++; - if ((!rport->pid) || (!rport->pwwn)) { - bfa_trc(rport->fcs, rport->pid); - bfa_sm_fault(rport->fcs, rport->pid); - } - if (bfa_fcs_lport_is_initiator(port)) { bfa_fcs_itnim_rport_online(rport->itnim); if (!BFA_FCS_PID_IS_WKA(rport->pid)) @@ -2078,7 +2047,6 @@ bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport) char rpwwn_buf[BFA_STRING_32]; rport->stats.offlines++; - rport->plogi_pending = BFA_FALSE; wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); wwn2str(rpwwn_buf, rport->pwwn); @@ -2152,7 +2120,7 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi) port->fabric->bb_credit = be16_to_cpu(plogi->csp.bbcred); bfa_fcport_set_tx_bbcredit(port->fcs->bfa, - port->fabric->bb_credit, 0); + port->fabric->bb_credit); } } @@ -2265,6 +2233,22 @@ bfa_fcs_rport_plogi_create(struct bfa_fcs_lport_s *port, struct fchs_s *fchs, bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD); } +static int +wwn_compare(wwn_t wwn1, wwn_t wwn2) +{ + u8 *b1 = (u8 *) &wwn1; + u8 *b2 = (u8 *) &wwn2; + int i; + + for (i = 0; i < sizeof(wwn_t); i++) { + if (b1[i] < b2[i]) + return -1; + if (b1[i] > b2[i]) + return 1; + } + return 0; +} + /* * Called by bport/vport to handle PLOGI received from an existing * remote port. @@ -2282,8 +2266,19 @@ bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, rport->reply_oxid = rx_fchs->ox_id; bfa_trc(rport->fcs, rport->reply_oxid); - rport->pid = rx_fchs->s_id; - bfa_trc(rport->fcs, rport->pid); + /* + * In Switched fabric topology, + * PLOGI to each other. If our pwwn is smaller, ignore it, + * if it is not a well known address. + * If the link topology is N2N, + * this Plogi should be accepted. + */ + if ((wwn_compare(rport->port->port_cfg.pwwn, rport->pwwn) == -1) && + (bfa_fcs_fabric_is_switched(rport->port->fabric)) && + (!BFA_FCS_PID_IS_WKA(rport->pid))) { + bfa_trc(rport->fcs, rport->pid); + return; + } rport->stats.plogi_rcvd++; bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD); @@ -2536,45 +2531,7 @@ bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, __be16 ox_id) bfa_sm_send_event(rport, RPSM_EVENT_PRLO_RCVD); } -void -bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, - struct bfa_rport_attr_s *rport_attr) -{ - struct bfa_rport_qos_attr_s qos_attr; - struct bfa_fcs_lport_s *port = rport->port; - bfa_port_speed_t rport_speed = rport->rpf.rpsc_speed; - - memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s)); - memset(&qos_attr, 0, sizeof(struct bfa_rport_qos_attr_s)); - - rport_attr->pid = rport->pid; - rport_attr->pwwn = rport->pwwn; - rport_attr->nwwn = rport->nwwn; - rport_attr->cos_supported = rport->fc_cos; - rport_attr->df_sz = rport->maxfrsize; - rport_attr->state = bfa_fcs_rport_get_state(rport); - rport_attr->fc_cos = rport->fc_cos; - rport_attr->cisc = rport->cisc; - rport_attr->scsi_function = rport->scsi_function; - rport_attr->curr_speed = rport->rpf.rpsc_speed; - rport_attr->assigned_speed = rport->rpf.assigned_speed; - - qos_attr.qos_priority = rport->bfa_rport->qos_attr.qos_priority; - qos_attr.qos_flow_id = - cpu_to_be32(rport->bfa_rport->qos_attr.qos_flow_id); - rport_attr->qos_attr = qos_attr; - - rport_attr->trl_enforced = BFA_FALSE; - if (bfa_fcport_is_ratelim(port->fcs->bfa) && - (rport->scsi_function == BFA_RPORT_TARGET)) { - if (rport_speed == BFA_PORT_SPEED_UNKNOWN) - rport_speed = - bfa_fcport_get_ratelim_speed(rport->fcs->bfa); - - if (rport_speed < bfa_fcs_lport_get_rport_max_speed(port)) - rport_attr->trl_enforced = BFA_TRUE; - } -} + /* * Remote port implementation. diff --git a/trunk/drivers/scsi/bfa/bfa_hw_cb.c b/trunk/drivers/scsi/bfa/bfa_hw_cb.c index e7ffd8205dc7..977e681ec803 100644 --- a/trunk/drivers/scsi/bfa/bfa_hw_cb.c +++ b/trunk/drivers/scsi/bfa/bfa_hw_cb.c @@ -17,14 +17,14 @@ #include "bfad_drv.h" #include "bfa_modules.h" -#include "bfi_reg.h" +#include "bfi_cbreg.h" void bfa_hwcb_reginit(struct bfa_s *bfa) { struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - int fn = bfa_ioc_pcifn(&bfa->ioc); + int i, q, fn = bfa_ioc_pcifn(&bfa->ioc); if (fn == 0) { bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS); @@ -33,6 +33,29 @@ bfa_hwcb_reginit(struct bfa_s *bfa) bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS); bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK); } + + for (i = 0; i < BFI_IOC_MAX_CQS; i++) { + /* + * CPE registers + */ + q = CPE_Q_NUM(fn, i); + bfa_regs->cpe_q_pi[i] = (kva + CPE_Q_PI(q)); + bfa_regs->cpe_q_ci[i] = (kva + CPE_Q_CI(q)); + bfa_regs->cpe_q_depth[i] = (kva + CPE_Q_DEPTH(q)); + + /* + * RME registers + */ + q = CPE_Q_NUM(fn, i); + bfa_regs->rme_q_pi[i] = (kva + RME_Q_PI(q)); + bfa_regs->rme_q_ci[i] = (kva + RME_Q_CI(q)); + bfa_regs->rme_q_depth[i] = (kva + RME_Q_DEPTH(q)); + } +} + +void +bfa_hwcb_reqq_ack(struct bfa_s *bfa, int reqq) +{ } static void @@ -42,6 +65,11 @@ bfa_hwcb_reqq_ack_msix(struct bfa_s *bfa, int reqq) bfa->iocfc.bfa_regs.intr_status); } +void +bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq) +{ +} + static void bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq) { @@ -75,72 +103,44 @@ bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, *num_vecs = __HFN_NUMINTS; } -/* - * Dummy interrupt handler for handling spurious interrupts. - */ -static void -bfa_hwcb_msix_dummy(struct bfa_s *bfa, int vec) -{ -} - /* * No special setup required for crossbow -- vector assignments are implicit. */ void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs) -{ - WARN_ON((nvecs != 1) && (nvecs != __HFN_NUMINTS)); - - bfa->msix.nvecs = nvecs; - bfa_hwcb_msix_uninstall(bfa); -} - -void -bfa_hwcb_msix_ctrl_install(struct bfa_s *bfa) { int i; - if (bfa->msix.nvecs == 0) - return; + WARN_ON((nvecs != 1) && (nvecs != __HFN_NUMINTS)); - if (bfa->msix.nvecs == 1) { - for (i = BFI_MSIX_CPE_QMIN_CB; i < BFI_MSIX_CB_MAX; i++) + bfa->msix.nvecs = nvecs; + if (nvecs == 1) { + for (i = 0; i < BFA_MSIX_CB_MAX; i++) bfa->msix.handler[i] = bfa_msix_all; return; } - for (i = BFI_MSIX_RME_QMAX_CB+1; i < BFI_MSIX_CB_MAX; i++) + for (i = BFA_MSIX_CPE_Q0; i <= BFA_MSIX_CPE_Q7; i++) + bfa->msix.handler[i] = bfa_msix_reqq; + + for (i = BFA_MSIX_RME_Q0; i <= BFA_MSIX_RME_Q7; i++) + bfa->msix.handler[i] = bfa_msix_rspq; + + for (; i < BFA_MSIX_CB_MAX; i++) bfa->msix.handler[i] = bfa_msix_lpu_err; } +/* + * Crossbow -- dummy, interrupts are masked + */ void -bfa_hwcb_msix_queue_install(struct bfa_s *bfa) +bfa_hwcb_msix_install(struct bfa_s *bfa) { - int i; - - if (bfa->msix.nvecs == 0) - return; - - if (bfa->msix.nvecs == 1) { - for (i = BFI_MSIX_CPE_QMIN_CB; i <= BFI_MSIX_RME_QMAX_CB; i++) - bfa->msix.handler[i] = bfa_msix_all; - return; - } - - for (i = BFI_MSIX_CPE_QMIN_CB; i <= BFI_MSIX_CPE_QMAX_CB; i++) - bfa->msix.handler[i] = bfa_msix_reqq; - - for (i = BFI_MSIX_RME_QMIN_CB; i <= BFI_MSIX_RME_QMAX_CB; i++) - bfa->msix.handler[i] = bfa_msix_rspq; } void bfa_hwcb_msix_uninstall(struct bfa_s *bfa) { - int i; - - for (i = 0; i < BFI_MSIX_CB_MAX; i++) - bfa->msix.handler[i] = bfa_hwcb_msix_dummy; } /* @@ -156,6 +156,6 @@ bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix) void bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end) { - *start = BFI_MSIX_RME_QMIN_CB; - *end = BFI_MSIX_RME_QMAX_CB; + *start = BFA_MSIX_RME_Q0; + *end = BFA_MSIX_RME_Q7; } diff --git a/trunk/drivers/scsi/bfa/bfa_hw_ct.c b/trunk/drivers/scsi/bfa/bfa_hw_ct.c index 989bbce9b296..21018d98a07b 100644 --- a/trunk/drivers/scsi/bfa/bfa_hw_ct.c +++ b/trunk/drivers/scsi/bfa/bfa_hw_ct.c @@ -17,10 +17,29 @@ #include "bfad_drv.h" #include "bfa_modules.h" -#include "bfi_reg.h" +#include "bfi_ctreg.h" BFA_TRC_FILE(HAL, IOCFC_CT); +static u32 __ct_msix_err_vec_reg[] = { + HOST_MSIX_ERR_INDEX_FN0, + HOST_MSIX_ERR_INDEX_FN1, + HOST_MSIX_ERR_INDEX_FN2, + HOST_MSIX_ERR_INDEX_FN3, +}; + +static void +bfa_hwct_msix_lpu_err_set(struct bfa_s *bfa, bfa_boolean_t msix, int vec) +{ + int fn = bfa_ioc_pcifn(&bfa->ioc); + void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); + + if (msix) + writel(vec, kva + __ct_msix_err_vec_reg[fn]); + else + writel(0, kva + __ct_msix_err_vec_reg[fn]); +} + /* * Dummy interrupt handler for handling spurious interrupt during chip-reinit. */ @@ -34,7 +53,7 @@ bfa_hwct_reginit(struct bfa_s *bfa) { struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - int fn = bfa_ioc_pcifn(&bfa->ioc); + int i, q, fn = bfa_ioc_pcifn(&bfa->ioc); if (fn == 0) { bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS); @@ -43,16 +62,26 @@ bfa_hwct_reginit(struct bfa_s *bfa) bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS); bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK); } -} - -void -bfa_hwct2_reginit(struct bfa_s *bfa) -{ - struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; - void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - bfa_regs->intr_status = (kva + CT2_HOSTFN_INT_STATUS); - bfa_regs->intr_mask = (kva + CT2_HOSTFN_INTR_MASK); + for (i = 0; i < BFI_IOC_MAX_CQS; i++) { + /* + * CPE registers + */ + q = CPE_Q_NUM(fn, i); + bfa_regs->cpe_q_pi[i] = (kva + CPE_PI_PTR_Q(q << 5)); + bfa_regs->cpe_q_ci[i] = (kva + CPE_CI_PTR_Q(q << 5)); + bfa_regs->cpe_q_depth[i] = (kva + CPE_DEPTH_Q(q << 5)); + bfa_regs->cpe_q_ctrl[i] = (kva + CPE_QCTRL_Q(q << 5)); + + /* + * RME registers + */ + q = CPE_Q_NUM(fn, i); + bfa_regs->rme_q_pi[i] = (kva + RME_PI_PTR_Q(q << 5)); + bfa_regs->rme_q_ci[i] = (kva + RME_CI_PTR_Q(q << 5)); + bfa_regs->rme_q_depth[i] = (kva + RME_DEPTH_Q(q << 5)); + bfa_regs->rme_q_ctrl[i] = (kva + RME_QCTRL_Q(q << 5)); + } } void @@ -77,9 +106,9 @@ void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, u32 *num_vecs, u32 *max_vec_bit) { - *msix_vecs_bmap = (1 << BFI_MSIX_CT_MAX) - 1; - *max_vec_bit = (1 << (BFI_MSIX_CT_MAX - 1)); - *num_vecs = BFI_MSIX_CT_MAX; + *msix_vecs_bmap = (1 << BFA_MSIX_CT_MAX) - 1; + *max_vec_bit = (1 << (BFA_MSIX_CT_MAX - 1)); + *num_vecs = BFA_MSIX_CT_MAX; } /* @@ -88,7 +117,7 @@ bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs) { - WARN_ON((nvecs != 1) && (nvecs != BFI_MSIX_CT_MAX)); + WARN_ON((nvecs != 1) && (nvecs != BFA_MSIX_CT_MAX)); bfa_trc(bfa, nvecs); bfa->msix.nvecs = nvecs; @@ -96,19 +125,7 @@ bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs) } void -bfa_hwct_msix_ctrl_install(struct bfa_s *bfa) -{ - if (bfa->msix.nvecs == 0) - return; - - if (bfa->msix.nvecs == 1) - bfa->msix.handler[BFI_MSIX_LPU_ERR_CT] = bfa_msix_all; - else - bfa->msix.handler[BFI_MSIX_LPU_ERR_CT] = bfa_msix_lpu_err; -} - -void -bfa_hwct_msix_queue_install(struct bfa_s *bfa) +bfa_hwct_msix_install(struct bfa_s *bfa) { int i; @@ -116,16 +133,19 @@ bfa_hwct_msix_queue_install(struct bfa_s *bfa) return; if (bfa->msix.nvecs == 1) { - for (i = BFI_MSIX_CPE_QMIN_CT; i < BFI_MSIX_CT_MAX; i++) + for (i = 0; i < BFA_MSIX_CT_MAX; i++) bfa->msix.handler[i] = bfa_msix_all; return; } - for (i = BFI_MSIX_CPE_QMIN_CT; i <= BFI_MSIX_CPE_QMAX_CT; i++) + for (i = BFA_MSIX_CPE_Q0; i <= BFA_MSIX_CPE_Q3; i++) bfa->msix.handler[i] = bfa_msix_reqq; - for (i = BFI_MSIX_RME_QMIN_CT; i <= BFI_MSIX_RME_QMAX_CT; i++) + for (; i <= BFA_MSIX_RME_Q3; i++) bfa->msix.handler[i] = bfa_msix_rspq; + + WARN_ON(i != BFA_MSIX_LPU_ERR); + bfa->msix.handler[BFA_MSIX_LPU_ERR] = bfa_msix_lpu_err; } void @@ -133,7 +153,7 @@ bfa_hwct_msix_uninstall(struct bfa_s *bfa) { int i; - for (i = 0; i < BFI_MSIX_CT_MAX; i++) + for (i = 0; i < BFA_MSIX_CT_MAX; i++) bfa->msix.handler[i] = bfa_hwct_msix_dummy; } @@ -144,12 +164,13 @@ void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix) { bfa_trc(bfa, 0); + bfa_hwct_msix_lpu_err_set(bfa, msix, BFA_MSIX_LPU_ERR); bfa_ioc_isr_mode_set(&bfa->ioc, msix); } void bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end) { - *start = BFI_MSIX_RME_QMIN_CT; - *end = BFI_MSIX_RME_QMAX_CT; + *start = BFA_MSIX_RME_Q0; + *end = BFA_MSIX_RME_Q3; } diff --git a/trunk/drivers/scsi/bfa/bfa_ioc.c b/trunk/drivers/scsi/bfa/bfa_ioc.c index d6c2bf3865d2..6c7e0339dda4 100644 --- a/trunk/drivers/scsi/bfa/bfa_ioc.c +++ b/trunk/drivers/scsi/bfa/bfa_ioc.c @@ -17,7 +17,7 @@ #include "bfad_drv.h" #include "bfa_ioc.h" -#include "bfi_reg.h" +#include "bfi_ctreg.h" #include "bfa_defs.h" #include "bfa_defs_svc.h" @@ -29,8 +29,8 @@ BFA_TRC_FILE(CNA, IOC); #define BFA_IOC_TOV 3000 /* msecs */ #define BFA_IOC_HWSEM_TOV 500 /* msecs */ #define BFA_IOC_HB_TOV 500 /* msecs */ +#define BFA_IOC_HWINIT_MAX 5 #define BFA_IOC_TOV_RECOVER BFA_IOC_HB_TOV -#define BFA_IOC_POLL_TOV BFA_TIMER_FREQ #define bfa_ioc_timer_start(__ioc) \ bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \ @@ -79,17 +79,14 @@ bfa_boolean_t bfa_auto_recover = BFA_TRUE; static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc); static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force); static void bfa_ioc_timeout(void *ioc); -static void bfa_ioc_poll_fwinit(struct bfa_ioc_s *ioc); static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc); static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc); static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc); static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc); static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc); -static void bfa_ioc_mbox_flush(struct bfa_ioc_s *ioc); +static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc); static void bfa_ioc_recover(struct bfa_ioc_s *ioc); static void bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc); -static void bfa_ioc_event_notify(struct bfa_ioc_s *ioc , - enum bfa_ioc_event_e event); static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc); static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc); static void bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc); @@ -108,12 +105,11 @@ enum ioc_event { IOC_E_ENABLED = 5, /* f/w enabled */ IOC_E_FWRSP_GETATTR = 6, /* IOC get attribute response */ IOC_E_DISABLED = 7, /* f/w disabled */ - IOC_E_PFFAILED = 8, /* failure notice by iocpf sm */ - IOC_E_HBFAIL = 9, /* heartbeat failure */ - IOC_E_HWERROR = 10, /* hardware error interrupt */ - IOC_E_TIMEOUT = 11, /* timeout */ - IOC_E_HWFAILED = 12, /* PCI mapping failure notice */ - IOC_E_FWRSP_ACQ_ADDR = 13, /* Acquiring address */ + IOC_E_INITFAILED = 8, /* failure notice by iocpf sm */ + IOC_E_PFFAILED = 9, /* failure notice by iocpf sm */ + IOC_E_HBFAIL = 10, /* heartbeat failure */ + IOC_E_HWERROR = 11, /* hardware error interrupt */ + IOC_E_TIMEOUT = 12, /* timeout */ }; bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc_s, enum ioc_event); @@ -125,8 +121,6 @@ bfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, acq_addr, struct bfa_ioc_s, enum ioc_event); static struct bfa_sm_table_s ioc_sm_table[] = { {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT}, @@ -138,8 +132,6 @@ static struct bfa_sm_table_s ioc_sm_table[] = { {BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL}, {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING}, {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED}, - {BFA_SM(bfa_ioc_sm_hwfail), BFA_IOC_HWFAIL}, - {BFA_SM(bfa_ioc_sm_acq_addr), BFA_IOC_ACQ_ADDR}, }; /* @@ -151,9 +143,9 @@ static struct bfa_sm_table_s ioc_sm_table[] = { bfa_iocpf_timeout, (__ioc), BFA_IOC_TOV) #define bfa_iocpf_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer) -#define bfa_iocpf_poll_timer_start(__ioc) \ +#define bfa_iocpf_recovery_timer_start(__ioc) \ bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \ - bfa_iocpf_poll_timeout, (__ioc), BFA_IOC_POLL_TOV) + bfa_iocpf_timeout, (__ioc), BFA_IOC_TOV_RECOVER) #define bfa_sem_timer_start(__ioc) \ bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->sem_timer, \ @@ -165,7 +157,6 @@ static struct bfa_sm_table_s ioc_sm_table[] = { */ static void bfa_iocpf_timeout(void *ioc_arg); static void bfa_iocpf_sem_timeout(void *ioc_arg); -static void bfa_iocpf_poll_timeout(void *ioc_arg); /* * IOCPF state machine events @@ -182,7 +173,6 @@ enum iocpf_event { IOCPF_E_GETATTRFAIL = 9, /* init fail notice by ioc sm */ IOCPF_E_SEMLOCKED = 10, /* h/w semaphore is locked */ IOCPF_E_TIMEOUT = 11, /* f/w response timeout */ - IOCPF_E_SEM_ERROR = 12, /* h/w sem mapping error */ }; /* @@ -324,16 +314,11 @@ bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event) /* !!! fall through !!! */ case IOC_E_HWERROR: ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); + bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry); if (event != IOC_E_PFFAILED) bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL); break; - case IOC_E_HWFAILED: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail); - break; - case IOC_E_DISABLE: bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); break; @@ -371,23 +356,17 @@ bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) case IOC_E_FWRSP_GETATTR: bfa_ioc_timer_stop(ioc); bfa_ioc_check_attr_wwns(ioc); - bfa_ioc_hb_monitor(ioc); bfa_fsm_set_state(ioc, bfa_ioc_sm_op); break; - case IOC_E_FWRSP_ACQ_ADDR: - bfa_ioc_timer_stop(ioc); - bfa_ioc_hb_monitor(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_acq_addr); break; - case IOC_E_PFFAILED: case IOC_E_HWERROR: bfa_ioc_timer_stop(ioc); /* !!! fall through !!! */ case IOC_E_TIMEOUT: ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); + bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry); if (event != IOC_E_PFFAILED) bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL); break; @@ -405,50 +384,6 @@ bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) } } -/* - * Acquiring address from fabric (entry function) - */ -static void -bfa_ioc_sm_acq_addr_entry(struct bfa_ioc_s *ioc) -{ -} - -/* - * Acquiring address from the fabric - */ -static void -bfa_ioc_sm_acq_addr(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_FWRSP_GETATTR: - bfa_ioc_check_attr_wwns(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_op); - break; - - case IOC_E_PFFAILED: - case IOC_E_HWERROR: - bfa_hb_timer_stop(ioc); - case IOC_E_HBFAIL: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); - if (event != IOC_E_PFFAILED) - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL); - break; - - case IOC_E_DISABLE: - bfa_hb_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); - break; - - case IOC_E_ENABLE: - break; - - default: - bfa_sm_fault(ioc, event); - } -} static void bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc) @@ -456,7 +391,7 @@ bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc) struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK); - bfa_ioc_event_notify(ioc, BFA_IOC_E_ENABLED); + bfa_ioc_hb_monitor(ioc); BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n"); } @@ -479,13 +414,13 @@ bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event) bfa_hb_timer_stop(ioc); /* !!! fall through !!! */ case IOC_E_HBFAIL: + bfa_ioc_fail_notify(ioc); + if (ioc->iocpf.auto_recover) bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry); else bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); - bfa_ioc_fail_notify(ioc); - if (event != IOC_E_PFFAILED) bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL); break; @@ -526,11 +461,6 @@ bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event) bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL); break; - case IOC_E_HWFAILED: - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail); - bfa_ioc_disable_comp(ioc); - break; - default: bfa_sm_fault(ioc, event); } @@ -595,14 +525,12 @@ bfa_ioc_sm_fail_retry(struct bfa_ioc_s *ioc, enum ioc_event event) * Initialization retry failed. */ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); if (event != IOC_E_PFFAILED) bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL); break; - case IOC_E_HWFAILED: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail); + case IOC_E_INITFAILED: + bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); break; case IOC_E_ENABLE: @@ -662,35 +590,6 @@ bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event) } } -static void -bfa_ioc_sm_hwfail_entry(struct bfa_ioc_s *ioc) -{ - bfa_trc(ioc, 0); -} - -static void -bfa_ioc_sm_hwfail(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_ENABLE: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - break; - - case IOC_E_DISABLE: - ioc->cbfn->disable_cbfn(ioc->bfa); - break; - - case IOC_E_DETACH: - bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - /* * IOCPF State Machine */ @@ -701,7 +600,7 @@ bfa_ioc_sm_hwfail(struct bfa_ioc_s *ioc, enum ioc_event event) static void bfa_iocpf_sm_reset_entry(struct bfa_iocpf_s *iocpf) { - iocpf->fw_mismatch_notified = BFA_FALSE; + iocpf->retry_count = 0; iocpf->auto_recover = bfa_auto_recover; } @@ -734,28 +633,6 @@ bfa_iocpf_sm_reset(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf_s *iocpf) { - struct bfi_ioc_image_hdr_s fwhdr; - u32 fwstate = readl(iocpf->ioc->ioc_regs.ioc_fwstate); - - /* h/w sem init */ - if (fwstate == BFI_IOC_UNINIT) - goto sem_get; - - bfa_ioc_fwver_get(iocpf->ioc, &fwhdr); - - if (swab32(fwhdr.exec) == BFI_FWBOOT_TYPE_NORMAL) - goto sem_get; - - bfa_trc(iocpf->ioc, fwstate); - bfa_trc(iocpf->ioc, fwhdr.exec); - writel(BFI_IOC_UNINIT, iocpf->ioc->ioc_regs.ioc_fwstate); - - /* - * Try to lock and then unlock the semaphore. - */ - readl(iocpf->ioc->ioc_regs.ioc_sem_reg); - writel(1, iocpf->ioc->ioc_regs.ioc_sem_reg); -sem_get: bfa_ioc_hw_sem_get(iocpf->ioc); } @@ -773,6 +650,7 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event) case IOCPF_E_SEMLOCKED: if (bfa_ioc_firmware_lock(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); } else { @@ -786,11 +664,6 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event) } break; - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - case IOCPF_E_DISABLE: bfa_sem_timer_stop(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); @@ -816,10 +689,10 @@ bfa_iocpf_sm_mismatch_entry(struct bfa_iocpf_s *iocpf) /* * Call only the first time sm enters fwmismatch state. */ - if (iocpf->fw_mismatch_notified == BFA_FALSE) + if (iocpf->retry_count == 0) bfa_ioc_pf_fwmismatch(iocpf->ioc); - iocpf->fw_mismatch_notified = BFA_TRUE; + iocpf->retry_count++; bfa_iocpf_timer_start(iocpf->ioc); } @@ -884,11 +757,6 @@ bfa_iocpf_sm_semwait(struct bfa_iocpf_s *iocpf, enum iocpf_event event) } break; - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - case IOCPF_E_DISABLE: bfa_sem_timer_stop(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); @@ -902,7 +770,7 @@ bfa_iocpf_sm_semwait(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_hwinit_entry(struct bfa_iocpf_s *iocpf) { - iocpf->poll_time = 0; + bfa_iocpf_timer_start(iocpf->ioc); bfa_ioc_hwinit(iocpf->ioc, BFA_FALSE); } @@ -919,12 +787,20 @@ bfa_iocpf_sm_hwinit(struct bfa_iocpf_s *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_FWREADY: + bfa_iocpf_timer_stop(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_enabling); break; + case IOCPF_E_INITFAIL: + bfa_iocpf_timer_stop(ioc); + /* + * !!! fall through !!! + */ + case IOCPF_E_TIMEOUT: writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_send_event(ioc, IOC_E_PFFAILED); + if (event == IOCPF_E_TIMEOUT) + bfa_fsm_send_event(ioc, IOC_E_PFFAILED); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync); break; @@ -944,10 +820,6 @@ static void bfa_iocpf_sm_enabling_entry(struct bfa_iocpf_s *iocpf) { bfa_iocpf_timer_start(iocpf->ioc); - /* - * Enable Interrupts before sending fw IOC ENABLE cmd. - */ - iocpf->ioc->cbfn->reset_cbfn(iocpf->ioc->bfa); bfa_ioc_send_enable(iocpf->ioc); } @@ -988,6 +860,10 @@ bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event) bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling); break; + case IOCPF_E_FWREADY: + bfa_ioc_send_enable(ioc); + break; + default: bfa_sm_fault(ioc, event); } @@ -1019,6 +895,16 @@ bfa_iocpf_sm_ready(struct bfa_iocpf_s *iocpf, enum iocpf_event event) bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync); break; + case IOCPF_E_FWREADY: + if (bfa_ioc_is_operational(ioc)) { + bfa_fsm_send_event(ioc, IOC_E_PFFAILED); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync); + } else { + bfa_fsm_send_event(ioc, IOC_E_PFFAILED); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync); + } + break; + default: bfa_sm_fault(ioc, event); } @@ -1043,6 +929,7 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_FWRSP_DISABLE: + case IOCPF_E_FWREADY: bfa_iocpf_timer_stop(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); break; @@ -1089,11 +976,6 @@ bfa_iocpf_sm_disabling_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); break; - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - case IOCPF_E_FAIL: break; @@ -1108,7 +990,6 @@ bfa_iocpf_sm_disabling_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_disabled_entry(struct bfa_iocpf_s *iocpf) { - bfa_ioc_mbox_flush(iocpf->ioc); bfa_fsm_send_event(iocpf->ioc, IOC_E_DISABLED); } @@ -1121,6 +1002,7 @@ bfa_iocpf_sm_disabled(struct bfa_iocpf_s *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_ENABLE: + iocpf->retry_count = 0; bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait); break; @@ -1137,7 +1019,6 @@ bfa_iocpf_sm_disabled(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf_s *iocpf) { - bfa_ioc_debug_save_ftrc(iocpf->ioc); bfa_ioc_hw_sem_get(iocpf->ioc); } @@ -1154,15 +1035,20 @@ bfa_iocpf_sm_initfail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_SEMLOCKED: bfa_ioc_notify_fail(ioc); - bfa_ioc_sync_leave(ioc); - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail); - break; - - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); + bfa_ioc_sync_ack(ioc); + iocpf->retry_count++; + if (iocpf->retry_count >= BFA_IOC_HWINIT_MAX) { + bfa_ioc_sync_leave(ioc); + writel(1, ioc->ioc_regs.ioc_sem_reg); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail); + } else { + if (bfa_ioc_sync_complete(ioc)) + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); + else { + writel(1, ioc->ioc_regs.ioc_sem_reg); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait); + } + } break; case IOCPF_E_DISABLE: @@ -1187,7 +1073,7 @@ bfa_iocpf_sm_initfail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_initfail_entry(struct bfa_iocpf_s *iocpf) { - bfa_trc(iocpf->ioc, 0); + bfa_fsm_send_event(iocpf->ioc, IOC_E_INITFAILED); } /* @@ -1226,7 +1112,7 @@ bfa_iocpf_sm_fail_sync_entry(struct bfa_iocpf_s *iocpf) /* * Flush any queued up mailbox requests. */ - bfa_ioc_mbox_flush(iocpf->ioc); + bfa_ioc_mbox_hbfail(iocpf->ioc); bfa_ioc_hw_sem_get(iocpf->ioc); } @@ -1240,11 +1126,11 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_SEMLOCKED: + iocpf->retry_count = 0; bfa_ioc_sync_ack(ioc); bfa_ioc_notify_fail(ioc); if (!iocpf->auto_recover) { bfa_ioc_sync_leave(ioc); - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); writel(1, ioc->ioc_regs.ioc_sem_reg); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); } else { @@ -1257,11 +1143,6 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) } break; - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - case IOCPF_E_DISABLE: bfa_sem_timer_stop(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); @@ -1278,7 +1159,6 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) static void bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf) { - bfa_trc(iocpf->ioc, 0); } /* @@ -1305,26 +1185,21 @@ bfa_iocpf_sm_fail(struct bfa_iocpf_s *iocpf, enum iocpf_event event) * BFA IOC private functions */ -/* - * Notify common modules registered for notification. - */ -static void -bfa_ioc_event_notify(struct bfa_ioc_s *ioc, enum bfa_ioc_event_e event) -{ - struct bfa_ioc_notify_s *notify; - struct list_head *qe; - - list_for_each(qe, &ioc->notify_q) { - notify = (struct bfa_ioc_notify_s *)qe; - notify->cbfn(notify->cbarg, event); - } -} - static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc) { + struct list_head *qe; + struct bfa_ioc_hbfail_notify_s *notify; + ioc->cbfn->disable_cbfn(ioc->bfa); - bfa_ioc_event_notify(ioc, BFA_IOC_E_DISABLED); + + /* + * Notify common modules registered for notification. + */ + list_for_each(qe, &ioc->hb_notify_q) { + notify = (struct bfa_ioc_hbfail_notify_s *) qe; + notify->cbfn(notify->cbarg); + } } bfa_boolean_t @@ -1336,15 +1211,16 @@ bfa_ioc_sem_get(void __iomem *sem_reg) r32 = readl(sem_reg); - while ((r32 & 1) && (cnt < BFA_SEM_SPINCNT)) { + while (r32 && (cnt < BFA_SEM_SPINCNT)) { cnt++; udelay(2); r32 = readl(sem_reg); } - if (!(r32 & 1)) + if (r32 == 0) return BFA_TRUE; + WARN_ON(cnt >= BFA_SEM_SPINCNT); return BFA_FALSE; } @@ -1358,12 +1234,7 @@ bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc) * will return 1. Semaphore is released by writing 1 to the register */ r32 = readl(ioc->ioc_regs.ioc_sem_reg); - if (r32 == ~0) { - WARN_ON(r32 == ~0); - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEM_ERROR); - return; - } - if (!(r32 & 1)) { + if (r32 == 0) { bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED); return; } @@ -1472,7 +1343,7 @@ bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) int i; drv_fwhdr = (struct bfi_ioc_image_hdr_s *) - bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); + bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0); for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) { if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) { @@ -1498,7 +1369,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env) bfa_ioc_fwver_get(ioc, &fwhdr); drv_fwhdr = (struct bfi_ioc_image_hdr_s *) - bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); + bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0); if (fwhdr.signature != drv_fwhdr->signature) { bfa_trc(ioc, fwhdr.signature); @@ -1506,8 +1377,8 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env) return BFA_FALSE; } - if (swab32(fwhdr.bootenv) != boot_env) { - bfa_trc(ioc, fwhdr.bootenv); + if (swab32(fwhdr.param) != boot_env) { + bfa_trc(ioc, fwhdr.param); bfa_trc(ioc, boot_env); return BFA_FALSE; } @@ -1543,8 +1414,8 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) bfa_trc(ioc, ioc_fwstate); - boot_type = BFI_FWBOOT_TYPE_NORMAL; - boot_env = BFI_FWBOOT_ENV_OS; + boot_type = BFI_BOOT_TYPE_NORMAL; + boot_env = BFI_BOOT_LOADER_OS; /* * check if firmware is valid @@ -1554,7 +1425,6 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) if (!fwvalid) { bfa_ioc_boot(ioc, boot_type, boot_env); - bfa_ioc_poll_fwinit(ioc); return; } @@ -1563,7 +1433,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) * just wait for an initialization completion interrupt. */ if (ioc_fwstate == BFI_IOC_INITING) { - bfa_ioc_poll_fwinit(ioc); + ioc->cbfn->reset_cbfn(ioc->bfa); return; } @@ -1582,6 +1452,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) * be flushed. Otherwise MSI-X interrupts are not delivered. */ bfa_ioc_msgflush(ioc); + ioc->cbfn->reset_cbfn(ioc->bfa); bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY); return; } @@ -1590,7 +1461,6 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) * Initialize the h/w for any other states. */ bfa_ioc_boot(ioc, boot_type, boot_env); - bfa_ioc_poll_fwinit(ioc); } static void @@ -1638,7 +1508,7 @@ bfa_ioc_send_enable(struct bfa_ioc_s *ioc) bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ, bfa_ioc_portid(ioc)); - enable_req.clscode = cpu_to_be16(ioc->clscode); + enable_req.ioc_class = ioc->ioc_mc; do_gettimeofday(&tv); enable_req.tv_sec = be32_to_cpu(tv.tv_sec); bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s)); @@ -1702,26 +1572,25 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, u32 loff = 0; u32 chunkno = 0; u32 i; - u32 asicmode; /* * Initialize LMEM first before code download */ bfa_ioc_lmem_init(ioc); - bfa_trc(ioc, bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc))); - fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), chunkno); + bfa_trc(ioc, bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc))); + fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno); pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff); pgoff = PSS_SMEM_PGOFF(loff); writel(pgnum, ioc->ioc_regs.host_page_num_fn); - for (i = 0; i < bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)); i++) { + for (i = 0; i < bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)); i++) { if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) { chunkno = BFA_IOC_FLASH_CHUNK_NO(i); - fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), + fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), BFA_IOC_FLASH_CHUNK_ADDR(chunkno)); } @@ -1747,15 +1616,11 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, ioc->ioc_regs.host_page_num_fn); /* - * Set boot type and device mode at the end. - */ - asicmode = BFI_FWBOOT_DEVMODE(ioc->asic_gen, ioc->asic_mode, - ioc->port0_mode, ioc->port1_mode); - bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_DEVMODE_OFF, - swab32(asicmode)); - bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_TYPE_OFF, + * Set boot type and boot param at the end. + */ + bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_TYPE_OFF, swab32(boot_type)); - bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_ENV_OFF, + bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_LOADER_OFF, swab32(boot_env)); } @@ -1771,7 +1636,6 @@ bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc) attr->adapter_prop = be32_to_cpu(attr->adapter_prop); attr->card_type = be32_to_cpu(attr->card_type); attr->maxfrsize = be16_to_cpu(attr->maxfrsize); - ioc->fcmode = (attr->port_mode == BFI_PORT_MODE_FC); bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR); } @@ -1826,7 +1690,7 @@ bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc) * Cleanup any pending requests. */ static void -bfa_ioc_mbox_flush(struct bfa_ioc_s *ioc) +bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc) { struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; struct bfa_mbox_cmd_s *cmd; @@ -1888,7 +1752,6 @@ bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz) /* * release semaphore. */ - readl(ioc->ioc_regs.ioc_init_sem_reg); writel(1, ioc->ioc_regs.ioc_init_sem_reg); bfa_trc(ioc, pgnum); @@ -1945,7 +1808,6 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz) /* * release semaphore. */ - readl(ioc->ioc_regs.ioc_init_sem_reg); writel(1, ioc->ioc_regs.ioc_init_sem_reg); bfa_trc(ioc, pgnum); return BFA_STATUS_OK; @@ -1954,13 +1816,18 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz) static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc) { + struct list_head *qe; + struct bfa_ioc_hbfail_notify_s *notify; struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; /* * Notify driver and common modules registered for notification. */ ioc->cbfn->hbfail_cbfn(ioc->bfa); - bfa_ioc_event_notify(ioc, BFA_IOC_E_FAILED); + list_for_each(qe, &ioc->hb_notify_q) { + notify = (struct bfa_ioc_hbfail_notify_s *) qe; + notify->cbfn(notify->cbarg); + } bfa_ioc_debug_save_ftrc(ioc); @@ -1997,7 +1864,6 @@ bfa_ioc_pll_init(struct bfa_ioc_s *ioc) /* * release semaphore. */ - readl(ioc->ioc_regs.ioc_init_sem_reg); writel(1, ioc->ioc_regs.ioc_init_sem_reg); return BFA_STATUS_OK; @@ -2010,6 +1876,8 @@ bfa_ioc_pll_init(struct bfa_ioc_s *ioc) void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_env) { + void __iomem *rb; + bfa_ioc_stats(ioc, ioc_boots); if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK) @@ -2018,16 +1886,22 @@ bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_env) /* * Initialize IOC state of all functions on a chip reset. */ - if (boot_type == BFI_FWBOOT_TYPE_MEMTEST) { - writel(BFI_IOC_MEMTEST, ioc->ioc_regs.ioc_fwstate); - writel(BFI_IOC_MEMTEST, ioc->ioc_regs.alt_ioc_fwstate); + rb = ioc->pcidev.pci_bar_kva; + 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 { - writel(BFI_IOC_INITING, ioc->ioc_regs.ioc_fwstate); - writel(BFI_IOC_INITING, ioc->ioc_regs.alt_ioc_fwstate); + writel(BFI_IOC_INITING, (rb + BFA_IOC0_STATE_REG)); + writel(BFI_IOC_INITING, (rb + BFA_IOC1_STATE_REG)); } bfa_ioc_msgflush(ioc); bfa_ioc_download_fw(ioc, boot_type, boot_env); + + /* + * Enable interrupts just before starting LPU + */ + ioc->cbfn->reset_cbfn(ioc->bfa); bfa_ioc_lpu_start(ioc); } @@ -2058,17 +1932,13 @@ bfa_ioc_is_initialized(struct bfa_ioc_s *ioc) (r32 != BFI_IOC_MEMTEST)); } -bfa_boolean_t +void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg) { __be32 *msgp = mbmsg; u32 r32; int i; - r32 = readl(ioc->ioc_regs.lpu_mbox_cmd); - if ((r32 & 1) == 0) - return BFA_FALSE; - /* * read the MBOX msg */ @@ -2084,8 +1954,6 @@ bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg) */ writel(1, ioc->ioc_regs.lpu_mbox_cmd); readl(ioc->ioc_regs.lpu_mbox_cmd); - - return BFA_TRUE; } void @@ -2102,10 +1970,11 @@ bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m) case BFI_IOC_I2H_HBEAT: break; + case BFI_IOC_I2H_READY_EVENT: + bfa_fsm_send_event(iocpf, IOCPF_E_FWREADY); + break; + case BFI_IOC_I2H_ENABLE_REPLY: - ioc->port_mode = ioc->port_mode_cfg = - (enum bfa_mode_s)msg->fw_event.port_mode; - ioc->ad_cap_bm = msg->fw_event.cap_bm; bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_ENABLE); break; @@ -2117,10 +1986,6 @@ bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m) bfa_ioc_getattr_reply(ioc); break; - case BFI_IOC_I2H_ACQ_ADDR_REPLY: - bfa_fsm_send_event(ioc, IOC_E_FWRSP_ACQ_ADDR); - break; - default: bfa_trc(ioc, msg->mh.msg_id); WARN_ON(1); @@ -2146,7 +2011,7 @@ bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn, ioc->iocpf.ioc = ioc; bfa_ioc_mbox_attach(ioc); - INIT_LIST_HEAD(&ioc->notify_q); + INIT_LIST_HEAD(&ioc->hb_notify_q); bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); bfa_fsm_send_event(ioc, IOC_E_RESET); @@ -2159,7 +2024,6 @@ void bfa_ioc_detach(struct bfa_ioc_s *ioc) { bfa_fsm_send_event(ioc, IOC_E_DETACH); - INIT_LIST_HEAD(&ioc->notify_q); } /* @@ -2169,80 +2033,20 @@ bfa_ioc_detach(struct bfa_ioc_s *ioc) */ void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, - enum bfi_pcifn_class clscode) + enum bfi_mclass mc) { - ioc->clscode = clscode; + ioc->ioc_mc = mc; ioc->pcidev = *pcidev; - - /* - * Initialize IOC and device personality - */ - ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_FC; - ioc->asic_mode = BFI_ASIC_MODE_FC; - - switch (pcidev->device_id) { - case BFA_PCI_DEVICE_ID_FC_8G1P: - case BFA_PCI_DEVICE_ID_FC_8G2P: - ioc->asic_gen = BFI_ASIC_GEN_CB; - ioc->fcmode = BFA_TRUE; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA; - ioc->ad_cap_bm = BFA_CM_HBA; - break; - - case BFA_PCI_DEVICE_ID_CT: - ioc->asic_gen = BFI_ASIC_GEN_CT; - ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH; - ioc->asic_mode = BFI_ASIC_MODE_ETH; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_CNA; - ioc->ad_cap_bm = BFA_CM_CNA; - break; - - case BFA_PCI_DEVICE_ID_CT_FC: - ioc->asic_gen = BFI_ASIC_GEN_CT; - ioc->fcmode = BFA_TRUE; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA; - ioc->ad_cap_bm = BFA_CM_HBA; - break; - - case BFA_PCI_DEVICE_ID_CT2: - ioc->asic_gen = BFI_ASIC_GEN_CT2; - if (clscode == BFI_PCIFN_CLASS_FC && - pcidev->ssid == BFA_PCI_CT2_SSID_FC) { - ioc->asic_mode = BFI_ASIC_MODE_FC16; - ioc->fcmode = BFA_TRUE; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA; - ioc->ad_cap_bm = BFA_CM_HBA; - } else { - ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH; - ioc->asic_mode = BFI_ASIC_MODE_ETH; - if (pcidev->ssid == BFA_PCI_CT2_SSID_FCoE) { - ioc->port_mode = - ioc->port_mode_cfg = BFA_MODE_CNA; - ioc->ad_cap_bm = BFA_CM_CNA; - } else { - ioc->port_mode = - ioc->port_mode_cfg = BFA_MODE_NIC; - ioc->ad_cap_bm = BFA_CM_NIC; - } - } - break; - - default: - WARN_ON(1); - } + ioc->ctdev = bfa_asic_id_ct(ioc->pcidev.device_id); + ioc->cna = ioc->ctdev && !ioc->fcmode; /* * Set asic specific interfaces. See bfa_ioc_cb.c and bfa_ioc_ct.c */ - if (ioc->asic_gen == BFI_ASIC_GEN_CB) - bfa_ioc_set_cb_hwif(ioc); - else if (ioc->asic_gen == BFI_ASIC_GEN_CT) + if (ioc->ctdev) bfa_ioc_set_ct_hwif(ioc); - else { - WARN_ON(ioc->asic_gen != BFI_ASIC_GEN_CT2); - bfa_ioc_set_ct2_hwif(ioc); - bfa_ioc_ct2_poweron(ioc); - } + else + bfa_ioc_set_cb_hwif(ioc); bfa_ioc_map_port(ioc); bfa_ioc_reg_init(ioc); @@ -2368,38 +2172,36 @@ bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc) struct bfi_mbmsg_s m; int mc; - if (bfa_ioc_msgget(ioc, &m)) { - /* - * Treat IOC message class as special. - */ - mc = m.mh.msg_class; - if (mc == BFI_MC_IOC) { - bfa_ioc_isr(ioc, &m); - return; - } - - if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL)) - return; + bfa_ioc_msgget(ioc, &m); - mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m); + /* + * Treat IOC message class as special. + */ + mc = m.mh.msg_class; + if (mc == BFI_MC_IOC) { + bfa_ioc_isr(ioc, &m); + return; } - bfa_ioc_lpu_read_stat(ioc); + if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL)) + return; - /* - * Try to send pending mailbox commands - */ - bfa_ioc_mbox_poll(ioc); + mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m); } void bfa_ioc_error_isr(struct bfa_ioc_s *ioc) { - bfa_ioc_stats(ioc, ioc_hbfails); - ioc->stats.hb_count = ioc->hb_count; bfa_fsm_send_event(ioc, IOC_E_HWERROR); } +void +bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc) +{ + ioc->fcmode = BFA_TRUE; + ioc->port_id = bfa_ioc_pcifn(ioc); +} + /* * return true if IOC is disabled */ @@ -2410,15 +2212,6 @@ bfa_ioc_is_disabled(struct bfa_ioc_s *ioc) bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled); } -/* - * Return TRUE if IOC is in acquiring address state - */ -bfa_boolean_t -bfa_ioc_is_acq_addr(struct bfa_ioc_s *ioc) -{ - return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_acq_addr); -} - /* * return true if IOC firmware is different. */ @@ -2446,16 +2239,17 @@ bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc) { u32 ioc_state; + void __iomem *rb = ioc->pcidev.pci_bar_kva; if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled)) return BFA_FALSE; - ioc_state = readl(ioc->ioc_regs.ioc_fwstate); + ioc_state = readl(rb + BFA_IOC0_STATE_REG); if (!bfa_ioc_state_disabled(ioc_state)) return BFA_FALSE; if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_FC_8G1P) { - ioc_state = readl(ioc->ioc_regs.alt_ioc_fwstate); + ioc_state = readl(rb + BFA_IOC1_STATE_REG); if (!bfa_ioc_state_disabled(ioc_state)) return BFA_FALSE; } @@ -2514,21 +2308,24 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver); - ad_attr->cna_capable = bfa_ioc_is_cna(ioc); - ad_attr->trunk_capable = (ad_attr->nports > 1) && - !bfa_ioc_is_cna(ioc) && !ad_attr->is_mezz; + ad_attr->cna_capable = ioc->cna; + ad_attr->trunk_capable = (ad_attr->nports > 1) && !ioc->cna && + !ad_attr->is_mezz; } enum bfa_ioc_type_e bfa_ioc_get_type(struct bfa_ioc_s *ioc) { - if (ioc->clscode == BFI_PCIFN_CLASS_ETH) + if (!ioc->ctdev || ioc->fcmode) + return BFA_IOC_TYPE_FC; + else if (ioc->ioc_mc == BFI_MC_IOCFC) + return BFA_IOC_TYPE_FCoE; + else if (ioc->ioc_mc == BFI_MC_LL) return BFA_IOC_TYPE_LL; - - WARN_ON(ioc->clscode != BFI_PCIFN_CLASS_FC); - - return (ioc->attr->port_mode == BFI_PORT_MODE_FC) - ? BFA_IOC_TYPE_FC : BFA_IOC_TYPE_FCoE; + else { + WARN_ON(ioc->ioc_mc != BFI_MC_LL); + return BFA_IOC_TYPE_LL; + } } void @@ -2587,8 +2384,11 @@ bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model) ioc_attr = ioc->attr; + /* + * model name + */ snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u", - BFA_MFG_NAME, ioc_attr->card_type); + BFA_MFG_NAME, ioc_attr->card_type); } enum bfa_ioc_state @@ -2638,9 +2438,6 @@ bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr) ioc_attr->state = bfa_ioc_get_state(ioc); ioc_attr->port_id = ioc->port_id; - ioc_attr->port_mode = ioc->port_mode; - ioc_attr->port_mode_cfg = ioc->port_mode_cfg; - ioc_attr->cap_bm = ioc->ad_cap_bm; ioc_attr->ioc_type = bfa_ioc_get_type(ioc); @@ -2678,6 +2475,12 @@ bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc) return m; } +bfa_boolean_t +bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc) +{ + return ioc->fcmode || !bfa_asic_id_ct(ioc->pcidev.device_id); +} + /* * Retrieve saved firmware trace from a prior IOC failure. */ @@ -2728,7 +2531,7 @@ bfa_ioc_send_fwsync(struct bfa_ioc_s *ioc) bfi_h2i_set(req->mh, BFI_MC_IOC, BFI_IOC_H2I_DBG_SYNC, bfa_ioc_portid(ioc)); - req->clscode = cpu_to_be16(ioc->clscode); + req->ioc_class = ioc->ioc_mc; bfa_ioc_mbox_queue(ioc, &cmd); } @@ -2870,7 +2673,6 @@ static void bfa_ioc_recover(struct bfa_ioc_s *ioc) { bfa_ioc_stats(ioc, ioc_hbfails); - ioc->stats.hb_count = ioc->hb_count; bfa_fsm_send_event(ioc, IOC_E_HBFAIL); } @@ -2901,34 +2703,6 @@ bfa_iocpf_sem_timeout(void *ioc_arg) bfa_ioc_hw_sem_get(ioc); } -static void -bfa_ioc_poll_fwinit(struct bfa_ioc_s *ioc) -{ - u32 fwstate = readl(ioc->ioc_regs.ioc_fwstate); - - bfa_trc(ioc, fwstate); - - if (fwstate == BFI_IOC_DISABLED) { - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY); - return; - } - - if (ioc->iocpf.poll_time >= BFA_IOC_TOV) - bfa_iocpf_timeout(ioc); - else { - ioc->iocpf.poll_time += BFA_IOC_POLL_TOV; - bfa_iocpf_poll_timer_start(ioc); - } -} - -static void -bfa_iocpf_poll_timeout(void *ioc_arg) -{ - struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg; - - bfa_ioc_poll_fwinit(ioc); -} - /* * bfa timer function */ @@ -2996,2423 +2770,3 @@ bfa_timer_stop(struct bfa_timer_s *timer) list_del(&timer->qe); } - -/* - * ASIC block related - */ -static void -bfa_ablk_config_swap(struct bfa_ablk_cfg_s *cfg) -{ - struct bfa_ablk_cfg_inst_s *cfg_inst; - int i, j; - u16 be16; - u32 be32; - - for (i = 0; i < BFA_ABLK_MAX; i++) { - cfg_inst = &cfg->inst[i]; - for (j = 0; j < BFA_ABLK_MAX_PFS; j++) { - be16 = cfg_inst->pf_cfg[j].pers; - cfg_inst->pf_cfg[j].pers = be16_to_cpu(be16); - be16 = cfg_inst->pf_cfg[j].num_qpairs; - cfg_inst->pf_cfg[j].num_qpairs = be16_to_cpu(be16); - be16 = cfg_inst->pf_cfg[j].num_vectors; - cfg_inst->pf_cfg[j].num_vectors = be16_to_cpu(be16); - be32 = cfg_inst->pf_cfg[j].bw; - cfg_inst->pf_cfg[j].bw = be16_to_cpu(be32); - } - } -} - -static void -bfa_ablk_isr(void *cbarg, struct bfi_mbmsg_s *msg) -{ - struct bfa_ablk_s *ablk = (struct bfa_ablk_s *)cbarg; - struct bfi_ablk_i2h_rsp_s *rsp = (struct bfi_ablk_i2h_rsp_s *)msg; - bfa_ablk_cbfn_t cbfn; - - WARN_ON(msg->mh.msg_class != BFI_MC_ABLK); - bfa_trc(ablk->ioc, msg->mh.msg_id); - - switch (msg->mh.msg_id) { - case BFI_ABLK_I2H_QUERY: - if (rsp->status == BFA_STATUS_OK) { - memcpy(ablk->cfg, ablk->dma_addr.kva, - sizeof(struct bfa_ablk_cfg_s)); - bfa_ablk_config_swap(ablk->cfg); - ablk->cfg = NULL; - } - break; - - case BFI_ABLK_I2H_ADPT_CONFIG: - case BFI_ABLK_I2H_PORT_CONFIG: - /* update config port mode */ - ablk->ioc->port_mode_cfg = rsp->port_mode; - - case BFI_ABLK_I2H_PF_DELETE: - case BFI_ABLK_I2H_PF_UPDATE: - case BFI_ABLK_I2H_OPTROM_ENABLE: - case BFI_ABLK_I2H_OPTROM_DISABLE: - /* No-op */ - break; - - case BFI_ABLK_I2H_PF_CREATE: - *(ablk->pcifn) = rsp->pcifn; - ablk->pcifn = NULL; - break; - - default: - WARN_ON(1); - } - - ablk->busy = BFA_FALSE; - if (ablk->cbfn) { - cbfn = ablk->cbfn; - ablk->cbfn = NULL; - cbfn(ablk->cbarg, rsp->status); - } -} - -static void -bfa_ablk_notify(void *cbarg, enum bfa_ioc_event_e event) -{ - struct bfa_ablk_s *ablk = (struct bfa_ablk_s *)cbarg; - - bfa_trc(ablk->ioc, event); - - switch (event) { - case BFA_IOC_E_ENABLED: - WARN_ON(ablk->busy != BFA_FALSE); - break; - - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - /* Fail any pending requests */ - ablk->pcifn = NULL; - if (ablk->busy) { - if (ablk->cbfn) - ablk->cbfn(ablk->cbarg, BFA_STATUS_FAILED); - ablk->cbfn = NULL; - ablk->busy = BFA_FALSE; - } - break; - - default: - WARN_ON(1); - break; - } -} - -u32 -bfa_ablk_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct bfa_ablk_cfg_s), BFA_DMA_ALIGN_SZ); -} - -void -bfa_ablk_memclaim(struct bfa_ablk_s *ablk, u8 *dma_kva, u64 dma_pa) -{ - ablk->dma_addr.kva = dma_kva; - ablk->dma_addr.pa = dma_pa; -} - -void -bfa_ablk_attach(struct bfa_ablk_s *ablk, struct bfa_ioc_s *ioc) -{ - ablk->ioc = ioc; - - bfa_ioc_mbox_regisr(ablk->ioc, BFI_MC_ABLK, bfa_ablk_isr, ablk); - bfa_q_qe_init(&ablk->ioc_notify); - bfa_ioc_notify_init(&ablk->ioc_notify, bfa_ablk_notify, ablk); - list_add_tail(&ablk->ioc_notify.qe, &ablk->ioc->notify_q); -} - -bfa_status_t -bfa_ablk_query(struct bfa_ablk_s *ablk, struct bfa_ablk_cfg_s *ablk_cfg, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_query_s *m; - - WARN_ON(!ablk_cfg); - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cfg = ablk_cfg; - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_query_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_QUERY, - bfa_ioc_portid(ablk->ioc)); - bfa_dma_be_addr_set(m->addr, ablk->dma_addr.pa); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_pf_create(struct bfa_ablk_s *ablk, u16 *pcifn, - u8 port, enum bfi_pcifn_class personality, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_pf_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->pcifn = pcifn; - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_CREATE, - bfa_ioc_portid(ablk->ioc)); - m->pers = cpu_to_be16((u16)personality); - m->bw = cpu_to_be32(bw); - m->port = port; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_pf_delete(struct bfa_ablk_s *ablk, int pcifn, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_pf_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_DELETE, - bfa_ioc_portid(ablk->ioc)); - m->pcifn = (u8)pcifn; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_adapter_config(struct bfa_ablk_s *ablk, enum bfa_mode_s mode, - int max_pf, int max_vf, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_cfg_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_cfg_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_ADPT_CONFIG, - bfa_ioc_portid(ablk->ioc)); - m->mode = (u8)mode; - m->max_pf = (u8)max_pf; - m->max_vf = (u8)max_vf; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_port_config(struct bfa_ablk_s *ablk, int port, enum bfa_mode_s mode, - int max_pf, int max_vf, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_cfg_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_cfg_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PORT_CONFIG, - bfa_ioc_portid(ablk->ioc)); - m->port = (u8)port; - m->mode = (u8)mode; - m->max_pf = (u8)max_pf; - m->max_vf = (u8)max_vf; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_pf_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_UPDATE, - bfa_ioc_portid(ablk->ioc)); - m->pcifn = (u8)pcifn; - m->bw = cpu_to_be32(bw); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_optrom_en(struct bfa_ablk_s *ablk, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_optrom_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_optrom_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_OPTROM_ENABLE, - bfa_ioc_portid(ablk->ioc)); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_optrom_dis(struct bfa_ablk_s *ablk, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_optrom_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_optrom_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_OPTROM_DISABLE, - bfa_ioc_portid(ablk->ioc)); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -/* - * SFP module specific - */ - -/* forward declarations */ -static void bfa_sfp_getdata_send(struct bfa_sfp_s *sfp); -static void bfa_sfp_media_get(struct bfa_sfp_s *sfp); -static bfa_status_t bfa_sfp_speed_valid(struct bfa_sfp_s *sfp, - enum bfa_port_speed portspeed); - -static void -bfa_cb_sfp_show(struct bfa_sfp_s *sfp) -{ - bfa_trc(sfp, sfp->lock); - if (sfp->cbfn) - sfp->cbfn(sfp->cbarg, sfp->status); - sfp->lock = 0; - sfp->cbfn = NULL; -} - -static void -bfa_cb_sfp_state_query(struct bfa_sfp_s *sfp) -{ - bfa_trc(sfp, sfp->portspeed); - if (sfp->media) { - bfa_sfp_media_get(sfp); - if (sfp->state_query_cbfn) - sfp->state_query_cbfn(sfp->state_query_cbarg, - sfp->status); - sfp->media = NULL; - } - - if (sfp->portspeed) { - sfp->status = bfa_sfp_speed_valid(sfp, sfp->portspeed); - if (sfp->state_query_cbfn) - sfp->state_query_cbfn(sfp->state_query_cbarg, - sfp->status); - sfp->portspeed = BFA_PORT_SPEED_UNKNOWN; - } - - sfp->state_query_lock = 0; - sfp->state_query_cbfn = NULL; -} - -/* - * IOC event handler. - */ -static void -bfa_sfp_notify(void *sfp_arg, enum bfa_ioc_event_e event) -{ - struct bfa_sfp_s *sfp = sfp_arg; - - bfa_trc(sfp, event); - bfa_trc(sfp, sfp->lock); - bfa_trc(sfp, sfp->state_query_lock); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (sfp->lock) { - sfp->status = BFA_STATUS_IOC_FAILURE; - bfa_cb_sfp_show(sfp); - } - - if (sfp->state_query_lock) { - sfp->status = BFA_STATUS_IOC_FAILURE; - bfa_cb_sfp_state_query(sfp); - } - break; - - default: - break; - } -} - -/* - * SFP get data send - */ -static void -bfa_sfp_getdata_send(struct bfa_sfp_s *sfp) -{ - struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg; - - bfa_trc(sfp, req->memtype); - - /* build host command */ - bfi_h2i_set(req->mh, BFI_MC_SFP, BFI_SFP_H2I_SHOW, - bfa_ioc_portid(sfp->ioc)); - - /* send mbox cmd */ - bfa_ioc_mbox_queue(sfp->ioc, &sfp->mbcmd); -} - -/* - * SFP is valid, read sfp data - */ -static void -bfa_sfp_getdata(struct bfa_sfp_s *sfp, enum bfi_sfp_mem_e memtype) -{ - struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg; - - WARN_ON(sfp->lock != 0); - bfa_trc(sfp, sfp->state); - - sfp->lock = 1; - sfp->memtype = memtype; - req->memtype = memtype; - - /* Setup SG list */ - bfa_alen_set(&req->alen, sizeof(struct sfp_mem_s), sfp->dbuf_pa); - - bfa_sfp_getdata_send(sfp); -} - -/* - * SFP show complete - */ -static void -bfa_sfp_show_comp(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg) -{ - struct bfi_sfp_rsp_s *rsp = (struct bfi_sfp_rsp_s *) msg; - - if (!sfp->lock) { - /* - * receiving response after ioc failure - */ - bfa_trc(sfp, sfp->lock); - return; - } - - bfa_trc(sfp, rsp->status); - if (rsp->status == BFA_STATUS_OK) { - sfp->data_valid = 1; - if (sfp->state == BFA_SFP_STATE_VALID) - sfp->status = BFA_STATUS_OK; - else if (sfp->state == BFA_SFP_STATE_UNSUPPORT) - sfp->status = BFA_STATUS_SFP_UNSUPP; - else - bfa_trc(sfp, sfp->state); - } else { - sfp->data_valid = 0; - sfp->status = rsp->status; - /* sfpshow shouldn't change sfp state */ - } - - bfa_trc(sfp, sfp->memtype); - if (sfp->memtype == BFI_SFP_MEM_DIAGEXT) { - bfa_trc(sfp, sfp->data_valid); - if (sfp->data_valid) { - u32 size = sizeof(struct sfp_mem_s); - u8 *des = (u8 *) &(sfp->sfpmem->srlid_base); - memcpy(des, sfp->dbuf_kva, size); - } - /* - * Queue completion callback. - */ - bfa_cb_sfp_show(sfp); - } else - sfp->lock = 0; - - bfa_trc(sfp, sfp->state_query_lock); - if (sfp->state_query_lock) { - sfp->state = rsp->state; - /* Complete callback */ - bfa_cb_sfp_state_query(sfp); - } -} - -/* - * SFP query fw sfp state - */ -static void -bfa_sfp_state_query(struct bfa_sfp_s *sfp) -{ - struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg; - - /* Should not be doing query if not in _INIT state */ - WARN_ON(sfp->state != BFA_SFP_STATE_INIT); - WARN_ON(sfp->state_query_lock != 0); - bfa_trc(sfp, sfp->state); - - sfp->state_query_lock = 1; - req->memtype = 0; - - if (!sfp->lock) - bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL); -} - -static void -bfa_sfp_media_get(struct bfa_sfp_s *sfp) -{ - enum bfa_defs_sfp_media_e *media = sfp->media; - - *media = BFA_SFP_MEDIA_UNKNOWN; - - if (sfp->state == BFA_SFP_STATE_UNSUPPORT) - *media = BFA_SFP_MEDIA_UNSUPPORT; - else if (sfp->state == BFA_SFP_STATE_VALID) { - union sfp_xcvr_e10g_code_u e10g; - struct sfp_mem_s *sfpmem = (struct sfp_mem_s *)sfp->dbuf_kva; - u16 xmtr_tech = (sfpmem->srlid_base.xcvr[4] & 0x3) << 7 | - (sfpmem->srlid_base.xcvr[5] >> 1); - - e10g.b = sfpmem->srlid_base.xcvr[0]; - bfa_trc(sfp, e10g.b); - bfa_trc(sfp, xmtr_tech); - /* check fc transmitter tech */ - if ((xmtr_tech & SFP_XMTR_TECH_CU) || - (xmtr_tech & SFP_XMTR_TECH_CP) || - (xmtr_tech & SFP_XMTR_TECH_CA)) - *media = BFA_SFP_MEDIA_CU; - else if ((xmtr_tech & SFP_XMTR_TECH_EL_INTRA) || - (xmtr_tech & SFP_XMTR_TECH_EL_INTER)) - *media = BFA_SFP_MEDIA_EL; - else if ((xmtr_tech & SFP_XMTR_TECH_LL) || - (xmtr_tech & SFP_XMTR_TECH_LC)) - *media = BFA_SFP_MEDIA_LW; - else if ((xmtr_tech & SFP_XMTR_TECH_SL) || - (xmtr_tech & SFP_XMTR_TECH_SN) || - (xmtr_tech & SFP_XMTR_TECH_SA)) - *media = BFA_SFP_MEDIA_SW; - /* Check 10G Ethernet Compilance code */ - else if (e10g.b & 0x10) - *media = BFA_SFP_MEDIA_SW; - else if (e10g.b & 0x60) - *media = BFA_SFP_MEDIA_LW; - else if (e10g.r.e10g_unall & 0x80) - *media = BFA_SFP_MEDIA_UNKNOWN; - else - bfa_trc(sfp, 0); - } else - bfa_trc(sfp, sfp->state); -} - -static bfa_status_t -bfa_sfp_speed_valid(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed) -{ - struct sfp_mem_s *sfpmem = (struct sfp_mem_s *)sfp->dbuf_kva; - struct sfp_xcvr_s *xcvr = (struct sfp_xcvr_s *) sfpmem->srlid_base.xcvr; - union sfp_xcvr_fc3_code_u fc3 = xcvr->fc3; - union sfp_xcvr_e10g_code_u e10g = xcvr->e10g; - - if (portspeed == BFA_PORT_SPEED_10GBPS) { - if (e10g.r.e10g_sr || e10g.r.e10g_lr) - return BFA_STATUS_OK; - else { - bfa_trc(sfp, e10g.b); - return BFA_STATUS_UNSUPP_SPEED; - } - } - if (((portspeed & BFA_PORT_SPEED_16GBPS) && fc3.r.mb1600) || - ((portspeed & BFA_PORT_SPEED_8GBPS) && fc3.r.mb800) || - ((portspeed & BFA_PORT_SPEED_4GBPS) && fc3.r.mb400) || - ((portspeed & BFA_PORT_SPEED_2GBPS) && fc3.r.mb200) || - ((portspeed & BFA_PORT_SPEED_1GBPS) && fc3.r.mb100)) - return BFA_STATUS_OK; - else { - bfa_trc(sfp, portspeed); - bfa_trc(sfp, fc3.b); - bfa_trc(sfp, e10g.b); - return BFA_STATUS_UNSUPP_SPEED; - } -} - -/* - * SFP hmbox handler - */ -void -bfa_sfp_intr(void *sfparg, struct bfi_mbmsg_s *msg) -{ - struct bfa_sfp_s *sfp = sfparg; - - switch (msg->mh.msg_id) { - case BFI_SFP_I2H_SHOW: - bfa_sfp_show_comp(sfp, msg); - break; - - case BFI_SFP_I2H_SCN: - bfa_trc(sfp, msg->mh.msg_id); - break; - - default: - bfa_trc(sfp, msg->mh.msg_id); - WARN_ON(1); - } -} - -/* - * Return DMA memory needed by sfp module. - */ -u32 -bfa_sfp_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ); -} - -/* - * Attach virtual and physical memory for SFP. - */ -void -bfa_sfp_attach(struct bfa_sfp_s *sfp, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod) -{ - sfp->dev = dev; - sfp->ioc = ioc; - sfp->trcmod = trcmod; - - sfp->cbfn = NULL; - sfp->cbarg = NULL; - sfp->sfpmem = NULL; - sfp->lock = 0; - sfp->data_valid = 0; - sfp->state = BFA_SFP_STATE_INIT; - sfp->state_query_lock = 0; - sfp->state_query_cbfn = NULL; - sfp->state_query_cbarg = NULL; - sfp->media = NULL; - sfp->portspeed = BFA_PORT_SPEED_UNKNOWN; - sfp->is_elb = BFA_FALSE; - - bfa_ioc_mbox_regisr(sfp->ioc, BFI_MC_SFP, bfa_sfp_intr, sfp); - bfa_q_qe_init(&sfp->ioc_notify); - bfa_ioc_notify_init(&sfp->ioc_notify, bfa_sfp_notify, sfp); - list_add_tail(&sfp->ioc_notify.qe, &sfp->ioc->notify_q); -} - -/* - * Claim Memory for SFP - */ -void -bfa_sfp_memclaim(struct bfa_sfp_s *sfp, u8 *dm_kva, u64 dm_pa) -{ - sfp->dbuf_kva = dm_kva; - sfp->dbuf_pa = dm_pa; - memset(sfp->dbuf_kva, 0, sizeof(struct sfp_mem_s)); - - dm_kva += BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ); - dm_pa += BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ); -} - -/* - * Show SFP eeprom content - * - * @param[in] sfp - bfa sfp module - * - * @param[out] sfpmem - sfp eeprom data - * - */ -bfa_status_t -bfa_sfp_show(struct bfa_sfp_s *sfp, struct sfp_mem_s *sfpmem, - bfa_cb_sfp_t cbfn, void *cbarg) -{ - - if (!bfa_ioc_is_operational(sfp->ioc)) { - bfa_trc(sfp, 0); - return BFA_STATUS_IOC_NON_OP; - } - - if (sfp->lock) { - bfa_trc(sfp, 0); - return BFA_STATUS_DEVBUSY; - } - - sfp->cbfn = cbfn; - sfp->cbarg = cbarg; - sfp->sfpmem = sfpmem; - - bfa_sfp_getdata(sfp, BFI_SFP_MEM_DIAGEXT); - return BFA_STATUS_OK; -} - -/* - * Return SFP Media type - * - * @param[in] sfp - bfa sfp module - * - * @param[out] media - port speed from user - * - */ -bfa_status_t -bfa_sfp_media(struct bfa_sfp_s *sfp, enum bfa_defs_sfp_media_e *media, - bfa_cb_sfp_t cbfn, void *cbarg) -{ - if (!bfa_ioc_is_operational(sfp->ioc)) { - bfa_trc(sfp, 0); - return BFA_STATUS_IOC_NON_OP; - } - - sfp->media = media; - if (sfp->state == BFA_SFP_STATE_INIT) { - if (sfp->state_query_lock) { - bfa_trc(sfp, 0); - return BFA_STATUS_DEVBUSY; - } else { - sfp->state_query_cbfn = cbfn; - sfp->state_query_cbarg = cbarg; - bfa_sfp_state_query(sfp); - return BFA_STATUS_SFP_NOT_READY; - } - } - - bfa_sfp_media_get(sfp); - return BFA_STATUS_OK; -} - -/* - * Check if user set port speed is allowed by the SFP - * - * @param[in] sfp - bfa sfp module - * @param[in] portspeed - port speed from user - * - */ -bfa_status_t -bfa_sfp_speed(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed, - bfa_cb_sfp_t cbfn, void *cbarg) -{ - WARN_ON(portspeed == BFA_PORT_SPEED_UNKNOWN); - - if (!bfa_ioc_is_operational(sfp->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* For Mezz card, all speed is allowed */ - if (bfa_mfg_is_mezz(sfp->ioc->attr->card_type)) - return BFA_STATUS_OK; - - /* Check SFP state */ - sfp->portspeed = portspeed; - if (sfp->state == BFA_SFP_STATE_INIT) { - if (sfp->state_query_lock) { - bfa_trc(sfp, 0); - return BFA_STATUS_DEVBUSY; - } else { - sfp->state_query_cbfn = cbfn; - sfp->state_query_cbarg = cbarg; - bfa_sfp_state_query(sfp); - return BFA_STATUS_SFP_NOT_READY; - } - } - - if (sfp->state == BFA_SFP_STATE_REMOVED || - sfp->state == BFA_SFP_STATE_FAILED) { - bfa_trc(sfp, sfp->state); - return BFA_STATUS_NO_SFP_DEV; - } - - if (sfp->state == BFA_SFP_STATE_INSERTED) { - bfa_trc(sfp, sfp->state); - return BFA_STATUS_DEVBUSY; /* sfp is reading data */ - } - - /* For eloopback, all speed is allowed */ - if (sfp->is_elb) - return BFA_STATUS_OK; - - return bfa_sfp_speed_valid(sfp, portspeed); -} - -/* - * Flash module specific - */ - -/* - * FLASH DMA buffer should be big enough to hold both MFG block and - * asic block(64k) at the same time and also should be 2k aligned to - * avoid write segement to cross sector boundary. - */ -#define BFA_FLASH_SEG_SZ 2048 -#define BFA_FLASH_DMA_BUF_SZ \ - BFA_ROUNDUP(0x010000 + sizeof(struct bfa_mfg_block_s), BFA_FLASH_SEG_SZ) - -static void -bfa_flash_cb(struct bfa_flash_s *flash) -{ - flash->op_busy = 0; - if (flash->cbfn) - flash->cbfn(flash->cbarg, flash->status); -} - -static void -bfa_flash_notify(void *cbarg, enum bfa_ioc_event_e event) -{ - struct bfa_flash_s *flash = cbarg; - - bfa_trc(flash, event); - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (flash->op_busy) { - flash->status = BFA_STATUS_IOC_FAILURE; - flash->cbfn(flash->cbarg, flash->status); - flash->op_busy = 0; - } - break; - - default: - break; - } -} - -/* - * Send flash attribute query request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_query_send(void *cbarg) -{ - struct bfa_flash_s *flash = cbarg; - struct bfi_flash_query_req_s *msg = - (struct bfi_flash_query_req_s *) flash->mb.msg; - - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_QUERY_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_alen_set(&msg->alen, sizeof(struct bfa_flash_attr_s), - flash->dbuf_pa); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); -} - -/* - * Send flash write request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_write_send(struct bfa_flash_s *flash) -{ - struct bfi_flash_write_req_s *msg = - (struct bfi_flash_write_req_s *) flash->mb.msg; - u32 len; - - msg->type = be32_to_cpu(flash->type); - msg->instance = flash->instance; - msg->offset = be32_to_cpu(flash->addr_off + flash->offset); - len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ? - flash->residue : BFA_FLASH_DMA_BUF_SZ; - msg->length = be32_to_cpu(len); - - /* indicate if it's the last msg of the whole write operation */ - msg->last = (len == flash->residue) ? 1 : 0; - - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_WRITE_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_alen_set(&msg->alen, len, flash->dbuf_pa); - memcpy(flash->dbuf_kva, flash->ubuf + flash->offset, len); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); - - flash->residue -= len; - flash->offset += len; -} - -/* - * Send flash read request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_read_send(void *cbarg) -{ - struct bfa_flash_s *flash = cbarg; - struct bfi_flash_read_req_s *msg = - (struct bfi_flash_read_req_s *) flash->mb.msg; - u32 len; - - msg->type = be32_to_cpu(flash->type); - msg->instance = flash->instance; - msg->offset = be32_to_cpu(flash->addr_off + flash->offset); - len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ? - flash->residue : BFA_FLASH_DMA_BUF_SZ; - msg->length = be32_to_cpu(len); - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_READ_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_alen_set(&msg->alen, len, flash->dbuf_pa); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); -} - -/* - * Send flash erase request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_erase_send(void *cbarg) -{ - struct bfa_flash_s *flash = cbarg; - struct bfi_flash_erase_req_s *msg = - (struct bfi_flash_erase_req_s *) flash->mb.msg; - - msg->type = be32_to_cpu(flash->type); - msg->instance = flash->instance; - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_ERASE_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); -} - -/* - * Process flash response messages upon receiving interrupts. - * - * @param[in] flasharg - flash structure - * @param[in] msg - message structure - */ -static void -bfa_flash_intr(void *flasharg, struct bfi_mbmsg_s *msg) -{ - struct bfa_flash_s *flash = flasharg; - u32 status; - - union { - struct bfi_flash_query_rsp_s *query; - struct bfi_flash_erase_rsp_s *erase; - struct bfi_flash_write_rsp_s *write; - struct bfi_flash_read_rsp_s *read; - struct bfi_mbmsg_s *msg; - } m; - - m.msg = msg; - bfa_trc(flash, msg->mh.msg_id); - - if (!flash->op_busy && msg->mh.msg_id != BFI_FLASH_I2H_EVENT) { - /* receiving response after ioc failure */ - bfa_trc(flash, 0x9999); - return; - } - - switch (msg->mh.msg_id) { - case BFI_FLASH_I2H_QUERY_RSP: - status = be32_to_cpu(m.query->status); - bfa_trc(flash, status); - if (status == BFA_STATUS_OK) { - u32 i; - struct bfa_flash_attr_s *attr, *f; - - attr = (struct bfa_flash_attr_s *) flash->ubuf; - f = (struct bfa_flash_attr_s *) flash->dbuf_kva; - attr->status = be32_to_cpu(f->status); - attr->npart = be32_to_cpu(f->npart); - bfa_trc(flash, attr->status); - bfa_trc(flash, attr->npart); - for (i = 0; i < attr->npart; i++) { - attr->part[i].part_type = - be32_to_cpu(f->part[i].part_type); - attr->part[i].part_instance = - be32_to_cpu(f->part[i].part_instance); - attr->part[i].part_off = - be32_to_cpu(f->part[i].part_off); - attr->part[i].part_size = - be32_to_cpu(f->part[i].part_size); - attr->part[i].part_len = - be32_to_cpu(f->part[i].part_len); - attr->part[i].part_status = - be32_to_cpu(f->part[i].part_status); - } - } - flash->status = status; - bfa_flash_cb(flash); - break; - case BFI_FLASH_I2H_ERASE_RSP: - status = be32_to_cpu(m.erase->status); - bfa_trc(flash, status); - flash->status = status; - bfa_flash_cb(flash); - break; - case BFI_FLASH_I2H_WRITE_RSP: - status = be32_to_cpu(m.write->status); - bfa_trc(flash, status); - if (status != BFA_STATUS_OK || flash->residue == 0) { - flash->status = status; - bfa_flash_cb(flash); - } else { - bfa_trc(flash, flash->offset); - bfa_flash_write_send(flash); - } - break; - case BFI_FLASH_I2H_READ_RSP: - status = be32_to_cpu(m.read->status); - bfa_trc(flash, status); - if (status != BFA_STATUS_OK) { - flash->status = status; - bfa_flash_cb(flash); - } else { - u32 len = be32_to_cpu(m.read->length); - bfa_trc(flash, flash->offset); - bfa_trc(flash, len); - memcpy(flash->ubuf + flash->offset, - flash->dbuf_kva, len); - flash->residue -= len; - flash->offset += len; - if (flash->residue == 0) { - flash->status = status; - bfa_flash_cb(flash); - } else - bfa_flash_read_send(flash); - } - break; - case BFI_FLASH_I2H_BOOT_VER_RSP: - case BFI_FLASH_I2H_EVENT: - bfa_trc(flash, msg->mh.msg_id); - break; - - default: - WARN_ON(1); - } -} - -/* - * Flash memory info API. - * - * @param[in] mincfg - minimal cfg variable - */ -u32 -bfa_flash_meminfo(bfa_boolean_t mincfg) -{ - /* min driver doesn't need flash */ - if (mincfg) - return 0; - return BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Flash attach API. - * - * @param[in] flash - flash structure - * @param[in] ioc - ioc structure - * @param[in] dev - device structure - * @param[in] trcmod - trace module - * @param[in] logmod - log module - */ -void -bfa_flash_attach(struct bfa_flash_s *flash, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg) -{ - flash->ioc = ioc; - flash->trcmod = trcmod; - flash->cbfn = NULL; - flash->cbarg = NULL; - flash->op_busy = 0; - - bfa_ioc_mbox_regisr(flash->ioc, BFI_MC_FLASH, bfa_flash_intr, flash); - bfa_q_qe_init(&flash->ioc_notify); - bfa_ioc_notify_init(&flash->ioc_notify, bfa_flash_notify, flash); - list_add_tail(&flash->ioc_notify.qe, &flash->ioc->notify_q); - - /* min driver doesn't need flash */ - if (mincfg) { - flash->dbuf_kva = NULL; - flash->dbuf_pa = 0; - } -} - -/* - * Claim memory for flash - * - * @param[in] flash - flash structure - * @param[in] dm_kva - pointer to virtual memory address - * @param[in] dm_pa - physical memory address - * @param[in] mincfg - minimal cfg variable - */ -void -bfa_flash_memclaim(struct bfa_flash_s *flash, u8 *dm_kva, u64 dm_pa, - bfa_boolean_t mincfg) -{ - if (mincfg) - return; - - flash->dbuf_kva = dm_kva; - flash->dbuf_pa = dm_pa; - memset(flash->dbuf_kva, 0, BFA_FLASH_DMA_BUF_SZ); - dm_kva += BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); - dm_pa += BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Get flash attribute. - * - * @param[in] flash - flash structure - * @param[in] attr - flash attribute structure - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_get_attr(struct bfa_flash_s *flash, struct bfa_flash_attr_s *attr, - bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_QUERY_REQ); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->ubuf = (u8 *) attr; - bfa_flash_query_send(flash); - - return BFA_STATUS_OK; -} - -/* - * Erase flash partition. - * - * @param[in] flash - flash structure - * @param[in] type - flash partition type - * @param[in] instance - flash partition instance - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_erase_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type, - u8 instance, bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_ERASE_REQ); - bfa_trc(flash, type); - bfa_trc(flash, instance); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->type = type; - flash->instance = instance; - - bfa_flash_erase_send(flash); - return BFA_STATUS_OK; -} - -/* - * Update flash partition. - * - * @param[in] flash - flash structure - * @param[in] type - flash partition type - * @param[in] instance - flash partition instance - * @param[in] buf - update data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to the partition starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_update_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type, - u8 instance, void *buf, u32 len, u32 offset, - bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_WRITE_REQ); - bfa_trc(flash, type); - bfa_trc(flash, instance); - bfa_trc(flash, len); - bfa_trc(flash, offset); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* - * 'len' must be in word (4-byte) boundary - * 'offset' must be in sector (16kb) boundary - */ - if (!len || (len & 0x03) || (offset & 0x00003FFF)) - return BFA_STATUS_FLASH_BAD_LEN; - - if (type == BFA_FLASH_PART_MFG) - return BFA_STATUS_EINVAL; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->type = type; - flash->instance = instance; - flash->residue = len; - flash->offset = 0; - flash->addr_off = offset; - flash->ubuf = buf; - - bfa_flash_write_send(flash); - return BFA_STATUS_OK; -} - -/* - * Read flash partition. - * - * @param[in] flash - flash structure - * @param[in] type - flash partition type - * @param[in] instance - flash partition instance - * @param[in] buf - read data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to the partition starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_read_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type, - u8 instance, void *buf, u32 len, u32 offset, - bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_READ_REQ); - bfa_trc(flash, type); - bfa_trc(flash, instance); - bfa_trc(flash, len); - bfa_trc(flash, offset); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* - * 'len' must be in word (4-byte) boundary - * 'offset' must be in sector (16kb) boundary - */ - if (!len || (len & 0x03) || (offset & 0x00003FFF)) - return BFA_STATUS_FLASH_BAD_LEN; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->type = type; - flash->instance = instance; - flash->residue = len; - flash->offset = 0; - flash->addr_off = offset; - flash->ubuf = buf; - bfa_flash_read_send(flash); - - return BFA_STATUS_OK; -} - -/* - * DIAG module specific - */ - -#define BFA_DIAG_MEMTEST_TOV 50000 /* memtest timeout in msec */ -#define BFA_DIAG_FWPING_TOV 1000 /* msec */ - -/* IOC event handler */ -static void -bfa_diag_notify(void *diag_arg, enum bfa_ioc_event_e event) -{ - struct bfa_diag_s *diag = diag_arg; - - bfa_trc(diag, event); - bfa_trc(diag, diag->block); - bfa_trc(diag, diag->fwping.lock); - bfa_trc(diag, diag->tsensor.lock); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (diag->fwping.lock) { - diag->fwping.status = BFA_STATUS_IOC_FAILURE; - diag->fwping.cbfn(diag->fwping.cbarg, - diag->fwping.status); - diag->fwping.lock = 0; - } - - if (diag->tsensor.lock) { - diag->tsensor.status = BFA_STATUS_IOC_FAILURE; - diag->tsensor.cbfn(diag->tsensor.cbarg, - diag->tsensor.status); - diag->tsensor.lock = 0; - } - - if (diag->block) { - if (diag->timer_active) { - bfa_timer_stop(&diag->timer); - diag->timer_active = 0; - } - - diag->status = BFA_STATUS_IOC_FAILURE; - diag->cbfn(diag->cbarg, diag->status); - diag->block = 0; - } - break; - - default: - break; - } -} - -static void -bfa_diag_memtest_done(void *cbarg) -{ - struct bfa_diag_s *diag = cbarg; - struct bfa_ioc_s *ioc = diag->ioc; - struct bfa_diag_memtest_result *res = diag->result; - u32 loff = BFI_BOOT_MEMTEST_RES_ADDR; - u32 pgnum, pgoff, i; - - pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff); - pgoff = PSS_SMEM_PGOFF(loff); - - writel(pgnum, ioc->ioc_regs.host_page_num_fn); - - for (i = 0; i < (sizeof(struct bfa_diag_memtest_result) / - sizeof(u32)); i++) { - /* read test result from smem */ - *((u32 *) res + i) = - bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); - loff += sizeof(u32); - } - - /* Reset IOC fwstates to BFI_IOC_UNINIT */ - bfa_ioc_reset_fwstate(ioc); - - res->status = swab32(res->status); - bfa_trc(diag, res->status); - - if (res->status == BFI_BOOT_MEMTEST_RES_SIG) - diag->status = BFA_STATUS_OK; - else { - diag->status = BFA_STATUS_MEMTEST_FAILED; - res->addr = swab32(res->addr); - res->exp = swab32(res->exp); - res->act = swab32(res->act); - res->err_status = swab32(res->err_status); - res->err_status1 = swab32(res->err_status1); - res->err_addr = swab32(res->err_addr); - bfa_trc(diag, res->addr); - bfa_trc(diag, res->exp); - bfa_trc(diag, res->act); - bfa_trc(diag, res->err_status); - bfa_trc(diag, res->err_status1); - bfa_trc(diag, res->err_addr); - } - diag->timer_active = 0; - diag->cbfn(diag->cbarg, diag->status); - diag->block = 0; -} - -/* - * Firmware ping - */ - -/* - * Perform DMA test directly - */ -static void -diag_fwping_send(struct bfa_diag_s *diag) -{ - struct bfi_diag_fwping_req_s *fwping_req; - u32 i; - - bfa_trc(diag, diag->fwping.dbuf_pa); - - /* fill DMA area with pattern */ - for (i = 0; i < (BFI_DIAG_DMA_BUF_SZ >> 2); i++) - *((u32 *)diag->fwping.dbuf_kva + i) = diag->fwping.data; - - /* Fill mbox msg */ - fwping_req = (struct bfi_diag_fwping_req_s *)diag->fwping.mbcmd.msg; - - /* Setup SG list */ - bfa_alen_set(&fwping_req->alen, BFI_DIAG_DMA_BUF_SZ, - diag->fwping.dbuf_pa); - /* Set up dma count */ - fwping_req->count = cpu_to_be32(diag->fwping.count); - /* Set up data pattern */ - fwping_req->data = diag->fwping.data; - - /* build host command */ - bfi_h2i_set(fwping_req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_FWPING, - bfa_ioc_portid(diag->ioc)); - - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->fwping.mbcmd); -} - -static void -diag_fwping_comp(struct bfa_diag_s *diag, - struct bfi_diag_fwping_rsp_s *diag_rsp) -{ - u32 rsp_data = diag_rsp->data; - u8 rsp_dma_status = diag_rsp->dma_status; - - bfa_trc(diag, rsp_data); - bfa_trc(diag, rsp_dma_status); - - if (rsp_dma_status == BFA_STATUS_OK) { - u32 i, pat; - pat = (diag->fwping.count & 0x1) ? ~(diag->fwping.data) : - diag->fwping.data; - /* Check mbox data */ - if (diag->fwping.data != rsp_data) { - bfa_trc(diag, rsp_data); - diag->fwping.result->dmastatus = - BFA_STATUS_DATACORRUPTED; - diag->fwping.status = BFA_STATUS_DATACORRUPTED; - diag->fwping.cbfn(diag->fwping.cbarg, - diag->fwping.status); - diag->fwping.lock = 0; - return; - } - /* Check dma pattern */ - for (i = 0; i < (BFI_DIAG_DMA_BUF_SZ >> 2); i++) { - if (*((u32 *)diag->fwping.dbuf_kva + i) != pat) { - bfa_trc(diag, i); - bfa_trc(diag, pat); - bfa_trc(diag, - *((u32 *)diag->fwping.dbuf_kva + i)); - diag->fwping.result->dmastatus = - BFA_STATUS_DATACORRUPTED; - diag->fwping.status = BFA_STATUS_DATACORRUPTED; - diag->fwping.cbfn(diag->fwping.cbarg, - diag->fwping.status); - diag->fwping.lock = 0; - return; - } - } - diag->fwping.result->dmastatus = BFA_STATUS_OK; - diag->fwping.status = BFA_STATUS_OK; - diag->fwping.cbfn(diag->fwping.cbarg, diag->fwping.status); - diag->fwping.lock = 0; - } else { - diag->fwping.status = BFA_STATUS_HDMA_FAILED; - diag->fwping.cbfn(diag->fwping.cbarg, diag->fwping.status); - diag->fwping.lock = 0; - } -} - -/* - * Temperature Sensor - */ - -static void -diag_tempsensor_send(struct bfa_diag_s *diag) -{ - struct bfi_diag_ts_req_s *msg; - - msg = (struct bfi_diag_ts_req_s *)diag->tsensor.mbcmd.msg; - bfa_trc(diag, msg->temp); - /* build host command */ - bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_TEMPSENSOR, - bfa_ioc_portid(diag->ioc)); - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->tsensor.mbcmd); -} - -static void -diag_tempsensor_comp(struct bfa_diag_s *diag, bfi_diag_ts_rsp_t *rsp) -{ - if (!diag->tsensor.lock) { - /* receiving response after ioc failure */ - bfa_trc(diag, diag->tsensor.lock); - return; - } - - /* - * ASIC junction tempsensor is a reg read operation - * it will always return OK - */ - diag->tsensor.temp->temp = be16_to_cpu(rsp->temp); - diag->tsensor.temp->ts_junc = rsp->ts_junc; - diag->tsensor.temp->ts_brd = rsp->ts_brd; - diag->tsensor.temp->status = BFA_STATUS_OK; - - if (rsp->ts_brd) { - if (rsp->status == BFA_STATUS_OK) { - diag->tsensor.temp->brd_temp = - be16_to_cpu(rsp->brd_temp); - } else { - bfa_trc(diag, rsp->status); - diag->tsensor.temp->brd_temp = 0; - diag->tsensor.temp->status = BFA_STATUS_DEVBUSY; - } - } - bfa_trc(diag, rsp->ts_junc); - bfa_trc(diag, rsp->temp); - bfa_trc(diag, rsp->ts_brd); - bfa_trc(diag, rsp->brd_temp); - diag->tsensor.cbfn(diag->tsensor.cbarg, diag->tsensor.status); - diag->tsensor.lock = 0; -} - -/* - * LED Test command - */ -static void -diag_ledtest_send(struct bfa_diag_s *diag, struct bfa_diag_ledtest_s *ledtest) -{ - struct bfi_diag_ledtest_req_s *msg; - - msg = (struct bfi_diag_ledtest_req_s *)diag->ledtest.mbcmd.msg; - /* build host command */ - bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_LEDTEST, - bfa_ioc_portid(diag->ioc)); - - /* - * convert the freq from N blinks per 10 sec to - * crossbow ontime value. We do it here because division is need - */ - if (ledtest->freq) - ledtest->freq = 500 / ledtest->freq; - - if (ledtest->freq == 0) - ledtest->freq = 1; - - bfa_trc(diag, ledtest->freq); - /* mcpy(&ledtest_req->req, ledtest, sizeof(bfa_diag_ledtest_t)); */ - msg->cmd = (u8) ledtest->cmd; - msg->color = (u8) ledtest->color; - msg->portid = bfa_ioc_portid(diag->ioc); - msg->led = ledtest->led; - msg->freq = cpu_to_be16(ledtest->freq); - - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->ledtest.mbcmd); -} - -static void -diag_ledtest_comp(struct bfa_diag_s *diag, struct bfi_diag_ledtest_rsp_s * msg) -{ - bfa_trc(diag, diag->ledtest.lock); - diag->ledtest.lock = BFA_FALSE; - /* no bfa_cb_queue is needed because driver is not waiting */ -} - -/* - * Port beaconing - */ -static void -diag_portbeacon_send(struct bfa_diag_s *diag, bfa_boolean_t beacon, u32 sec) -{ - struct bfi_diag_portbeacon_req_s *msg; - - msg = (struct bfi_diag_portbeacon_req_s *)diag->beacon.mbcmd.msg; - /* build host command */ - bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_PORTBEACON, - bfa_ioc_portid(diag->ioc)); - msg->beacon = beacon; - msg->period = cpu_to_be32(sec); - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->beacon.mbcmd); -} - -static void -diag_portbeacon_comp(struct bfa_diag_s *diag) -{ - bfa_trc(diag, diag->beacon.state); - diag->beacon.state = BFA_FALSE; - if (diag->cbfn_beacon) - diag->cbfn_beacon(diag->dev, BFA_FALSE, diag->beacon.link_e2e); -} - -/* - * Diag hmbox handler - */ -void -bfa_diag_intr(void *diagarg, struct bfi_mbmsg_s *msg) -{ - struct bfa_diag_s *diag = diagarg; - - switch (msg->mh.msg_id) { - case BFI_DIAG_I2H_PORTBEACON: - diag_portbeacon_comp(diag); - break; - case BFI_DIAG_I2H_FWPING: - diag_fwping_comp(diag, (struct bfi_diag_fwping_rsp_s *) msg); - break; - case BFI_DIAG_I2H_TEMPSENSOR: - diag_tempsensor_comp(diag, (bfi_diag_ts_rsp_t *) msg); - break; - case BFI_DIAG_I2H_LEDTEST: - diag_ledtest_comp(diag, (struct bfi_diag_ledtest_rsp_s *) msg); - break; - default: - bfa_trc(diag, msg->mh.msg_id); - WARN_ON(1); - } -} - -/* - * Gen RAM Test - * - * @param[in] *diag - diag data struct - * @param[in] *memtest - mem test params input from upper layer, - * @param[in] pattern - mem test pattern - * @param[in] *result - mem test result - * @param[in] cbfn - mem test callback functioin - * @param[in] cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_diag_memtest(struct bfa_diag_s *diag, struct bfa_diag_memtest_s *memtest, - u32 pattern, struct bfa_diag_memtest_result *result, - bfa_cb_diag_t cbfn, void *cbarg) -{ - bfa_trc(diag, pattern); - - if (!bfa_ioc_adapter_is_disabled(diag->ioc)) - return BFA_STATUS_ADAPTER_ENABLED; - - /* check to see if there is another destructive diag cmd running */ - if (diag->block) { - bfa_trc(diag, diag->block); - return BFA_STATUS_DEVBUSY; - } else - diag->block = 1; - - diag->result = result; - diag->cbfn = cbfn; - diag->cbarg = cbarg; - - /* download memtest code and take LPU0 out of reset */ - bfa_ioc_boot(diag->ioc, BFI_FWBOOT_TYPE_MEMTEST, BFI_FWBOOT_ENV_OS); - - bfa_timer_begin(diag->ioc->timer_mod, &diag->timer, - bfa_diag_memtest_done, diag, BFA_DIAG_MEMTEST_TOV); - diag->timer_active = 1; - return BFA_STATUS_OK; -} - -/* - * DIAG firmware ping command - * - * @param[in] *diag - diag data struct - * @param[in] cnt - dma loop count for testing PCIE - * @param[in] data - data pattern to pass in fw - * @param[in] *result - pt to bfa_diag_fwping_result_t data struct - * @param[in] cbfn - callback function - * @param[in] *cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_diag_fwping(struct bfa_diag_s *diag, u32 cnt, u32 data, - struct bfa_diag_results_fwping *result, bfa_cb_diag_t cbfn, - void *cbarg) -{ - bfa_trc(diag, cnt); - bfa_trc(diag, data); - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (bfa_asic_id_ct2(bfa_ioc_devid((diag->ioc))) && - ((diag->ioc)->clscode == BFI_PCIFN_CLASS_ETH)) - return BFA_STATUS_CMD_NOTSUPP; - - /* check to see if there is another destructive diag cmd running */ - if (diag->block || diag->fwping.lock) { - bfa_trc(diag, diag->block); - bfa_trc(diag, diag->fwping.lock); - return BFA_STATUS_DEVBUSY; - } - - /* Initialization */ - diag->fwping.lock = 1; - diag->fwping.cbfn = cbfn; - diag->fwping.cbarg = cbarg; - diag->fwping.result = result; - diag->fwping.data = data; - diag->fwping.count = cnt; - - /* Init test results */ - diag->fwping.result->data = 0; - diag->fwping.result->status = BFA_STATUS_OK; - - /* kick off the first ping */ - diag_fwping_send(diag); - return BFA_STATUS_OK; -} - -/* - * Read Temperature Sensor - * - * @param[in] *diag - diag data struct - * @param[in] *result - pt to bfa_diag_temp_t data struct - * @param[in] cbfn - callback function - * @param[in] *cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_diag_tsensor_query(struct bfa_diag_s *diag, - struct bfa_diag_results_tempsensor_s *result, - bfa_cb_diag_t cbfn, void *cbarg) -{ - /* check to see if there is a destructive diag cmd running */ - if (diag->block || diag->tsensor.lock) { - bfa_trc(diag, diag->block); - bfa_trc(diag, diag->tsensor.lock); - return BFA_STATUS_DEVBUSY; - } - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* Init diag mod params */ - diag->tsensor.lock = 1; - diag->tsensor.temp = result; - diag->tsensor.cbfn = cbfn; - diag->tsensor.cbarg = cbarg; - - /* Send msg to fw */ - diag_tempsensor_send(diag); - - return BFA_STATUS_OK; -} - -/* - * LED Test command - * - * @param[in] *diag - diag data struct - * @param[in] *ledtest - pt to ledtest data structure - * - * @param[out] - */ -bfa_status_t -bfa_diag_ledtest(struct bfa_diag_s *diag, struct bfa_diag_ledtest_s *ledtest) -{ - bfa_trc(diag, ledtest->cmd); - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (diag->beacon.state) - return BFA_STATUS_BEACON_ON; - - if (diag->ledtest.lock) - return BFA_STATUS_LEDTEST_OP; - - /* Send msg to fw */ - diag->ledtest.lock = BFA_TRUE; - diag_ledtest_send(diag, ledtest); - - return BFA_STATUS_OK; -} - -/* - * Port beaconing command - * - * @param[in] *diag - diag data struct - * @param[in] beacon - port beaconing 1:ON 0:OFF - * @param[in] link_e2e_beacon - link beaconing 1:ON 0:OFF - * @param[in] sec - beaconing duration in seconds - * - * @param[out] - */ -bfa_status_t -bfa_diag_beacon_port(struct bfa_diag_s *diag, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon, uint32_t sec) -{ - bfa_trc(diag, beacon); - bfa_trc(diag, link_e2e_beacon); - bfa_trc(diag, sec); - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (diag->ledtest.lock) - return BFA_STATUS_LEDTEST_OP; - - if (diag->beacon.state && beacon) /* beacon alread on */ - return BFA_STATUS_BEACON_ON; - - diag->beacon.state = beacon; - diag->beacon.link_e2e = link_e2e_beacon; - if (diag->cbfn_beacon) - diag->cbfn_beacon(diag->dev, beacon, link_e2e_beacon); - - /* Send msg to fw */ - diag_portbeacon_send(diag, beacon, sec); - - return BFA_STATUS_OK; -} - -/* - * Return DMA memory needed by diag module. - */ -u32 -bfa_diag_meminfo(void) -{ - return BFA_ROUNDUP(BFI_DIAG_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Attach virtual and physical memory for Diag. - */ -void -bfa_diag_attach(struct bfa_diag_s *diag, struct bfa_ioc_s *ioc, void *dev, - bfa_cb_diag_beacon_t cbfn_beacon, struct bfa_trc_mod_s *trcmod) -{ - diag->dev = dev; - diag->ioc = ioc; - diag->trcmod = trcmod; - - diag->block = 0; - diag->cbfn = NULL; - diag->cbarg = NULL; - diag->result = NULL; - diag->cbfn_beacon = cbfn_beacon; - - bfa_ioc_mbox_regisr(diag->ioc, BFI_MC_DIAG, bfa_diag_intr, diag); - bfa_q_qe_init(&diag->ioc_notify); - bfa_ioc_notify_init(&diag->ioc_notify, bfa_diag_notify, diag); - list_add_tail(&diag->ioc_notify.qe, &diag->ioc->notify_q); -} - -void -bfa_diag_memclaim(struct bfa_diag_s *diag, u8 *dm_kva, u64 dm_pa) -{ - diag->fwping.dbuf_kva = dm_kva; - diag->fwping.dbuf_pa = dm_pa; - memset(diag->fwping.dbuf_kva, 0, BFI_DIAG_DMA_BUF_SZ); -} - -/* - * PHY module specific - */ -#define BFA_PHY_DMA_BUF_SZ 0x02000 /* 8k dma buffer */ -#define BFA_PHY_LOCK_STATUS 0x018878 /* phy semaphore status reg */ - -static void -bfa_phy_ntoh32(u32 *obuf, u32 *ibuf, int sz) -{ - int i, m = sz >> 2; - - for (i = 0; i < m; i++) - obuf[i] = be32_to_cpu(ibuf[i]); -} - -static bfa_boolean_t -bfa_phy_present(struct bfa_phy_s *phy) -{ - return (phy->ioc->attr->card_type == BFA_MFG_TYPE_LIGHTNING); -} - -static void -bfa_phy_notify(void *cbarg, enum bfa_ioc_event_e event) -{ - struct bfa_phy_s *phy = cbarg; - - bfa_trc(phy, event); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (phy->op_busy) { - phy->status = BFA_STATUS_IOC_FAILURE; - phy->cbfn(phy->cbarg, phy->status); - phy->op_busy = 0; - } - break; - - default: - break; - } -} - -/* - * Send phy attribute query request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_query_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_query_req_s *msg = - (struct bfi_phy_query_req_s *) phy->mb.msg; - - msg->instance = phy->instance; - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_QUERY_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, sizeof(struct bfa_phy_attr_s), phy->dbuf_pa); - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); -} - -/* - * Send phy write request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_write_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_write_req_s *msg = - (struct bfi_phy_write_req_s *) phy->mb.msg; - u32 len; - u16 *buf, *dbuf; - int i, sz; - - msg->instance = phy->instance; - msg->offset = cpu_to_be32(phy->addr_off + phy->offset); - len = (phy->residue < BFA_PHY_DMA_BUF_SZ) ? - phy->residue : BFA_PHY_DMA_BUF_SZ; - msg->length = cpu_to_be32(len); - - /* indicate if it's the last msg of the whole write operation */ - msg->last = (len == phy->residue) ? 1 : 0; - - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_WRITE_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, len, phy->dbuf_pa); - - buf = (u16 *) (phy->ubuf + phy->offset); - dbuf = (u16 *)phy->dbuf_kva; - sz = len >> 1; - for (i = 0; i < sz; i++) - buf[i] = cpu_to_be16(dbuf[i]); - - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); - - phy->residue -= len; - phy->offset += len; -} - -/* - * Send phy read request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_read_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_read_req_s *msg = - (struct bfi_phy_read_req_s *) phy->mb.msg; - u32 len; - - msg->instance = phy->instance; - msg->offset = cpu_to_be32(phy->addr_off + phy->offset); - len = (phy->residue < BFA_PHY_DMA_BUF_SZ) ? - phy->residue : BFA_PHY_DMA_BUF_SZ; - msg->length = cpu_to_be32(len); - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_READ_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, len, phy->dbuf_pa); - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); -} - -/* - * Send phy stats request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_stats_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_stats_req_s *msg = - (struct bfi_phy_stats_req_s *) phy->mb.msg; - - msg->instance = phy->instance; - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_STATS_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, sizeof(struct bfa_phy_stats_s), phy->dbuf_pa); - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); -} - -/* - * Flash memory info API. - * - * @param[in] mincfg - minimal cfg variable - */ -u32 -bfa_phy_meminfo(bfa_boolean_t mincfg) -{ - /* min driver doesn't need phy */ - if (mincfg) - return 0; - - return BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Flash attach API. - * - * @param[in] phy - phy structure - * @param[in] ioc - ioc structure - * @param[in] dev - device structure - * @param[in] trcmod - trace module - * @param[in] logmod - log module - */ -void -bfa_phy_attach(struct bfa_phy_s *phy, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg) -{ - phy->ioc = ioc; - phy->trcmod = trcmod; - phy->cbfn = NULL; - phy->cbarg = NULL; - phy->op_busy = 0; - - bfa_ioc_mbox_regisr(phy->ioc, BFI_MC_PHY, bfa_phy_intr, phy); - bfa_q_qe_init(&phy->ioc_notify); - bfa_ioc_notify_init(&phy->ioc_notify, bfa_phy_notify, phy); - list_add_tail(&phy->ioc_notify.qe, &phy->ioc->notify_q); - - /* min driver doesn't need phy */ - if (mincfg) { - phy->dbuf_kva = NULL; - phy->dbuf_pa = 0; - } -} - -/* - * Claim memory for phy - * - * @param[in] phy - phy structure - * @param[in] dm_kva - pointer to virtual memory address - * @param[in] dm_pa - physical memory address - * @param[in] mincfg - minimal cfg variable - */ -void -bfa_phy_memclaim(struct bfa_phy_s *phy, u8 *dm_kva, u64 dm_pa, - bfa_boolean_t mincfg) -{ - if (mincfg) - return; - - phy->dbuf_kva = dm_kva; - phy->dbuf_pa = dm_pa; - memset(phy->dbuf_kva, 0, BFA_PHY_DMA_BUF_SZ); - dm_kva += BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); - dm_pa += BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -bfa_boolean_t -bfa_phy_busy(struct bfa_ioc_s *ioc) -{ - void __iomem *rb; - - rb = bfa_ioc_bar0(ioc); - return readl(rb + BFA_PHY_LOCK_STATUS); -} - -/* - * Get phy attribute. - * - * @param[in] phy - phy structure - * @param[in] attr - phy attribute structure - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_get_attr(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_attr_s *attr, bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_QUERY_REQ); - bfa_trc(phy, instance); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->ubuf = (uint8_t *) attr; - bfa_phy_query_send(phy); - - return BFA_STATUS_OK; -} - -/* - * Get phy stats. - * - * @param[in] phy - phy structure - * @param[in] instance - phy image instance - * @param[in] stats - pointer to phy stats - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_get_stats(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_stats_s *stats, - bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_STATS_REQ); - bfa_trc(phy, instance); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->ubuf = (u8 *) stats; - bfa_phy_stats_send(phy); - - return BFA_STATUS_OK; -} - -/* - * Update phy image. - * - * @param[in] phy - phy structure - * @param[in] instance - phy image instance - * @param[in] buf - update data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_update(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_WRITE_REQ); - bfa_trc(phy, instance); - bfa_trc(phy, len); - bfa_trc(phy, offset); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* 'len' must be in word (4-byte) boundary */ - if (!len || (len & 0x03)) - return BFA_STATUS_FAILED; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->residue = len; - phy->offset = 0; - phy->addr_off = offset; - phy->ubuf = buf; - - bfa_phy_write_send(phy); - return BFA_STATUS_OK; -} - -/* - * Read phy image. - * - * @param[in] phy - phy structure - * @param[in] instance - phy image instance - * @param[in] buf - read data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_read(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_READ_REQ); - bfa_trc(phy, instance); - bfa_trc(phy, len); - bfa_trc(phy, offset); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* 'len' must be in word (4-byte) boundary */ - if (!len || (len & 0x03)) - return BFA_STATUS_FAILED; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->residue = len; - phy->offset = 0; - phy->addr_off = offset; - phy->ubuf = buf; - bfa_phy_read_send(phy); - - return BFA_STATUS_OK; -} - -/* - * Process phy response messages upon receiving interrupts. - * - * @param[in] phyarg - phy structure - * @param[in] msg - message structure - */ -void -bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg) -{ - struct bfa_phy_s *phy = phyarg; - u32 status; - - union { - struct bfi_phy_query_rsp_s *query; - struct bfi_phy_stats_rsp_s *stats; - struct bfi_phy_write_rsp_s *write; - struct bfi_phy_read_rsp_s *read; - struct bfi_mbmsg_s *msg; - } m; - - m.msg = msg; - bfa_trc(phy, msg->mh.msg_id); - - if (!phy->op_busy) { - /* receiving response after ioc failure */ - bfa_trc(phy, 0x9999); - return; - } - - switch (msg->mh.msg_id) { - case BFI_PHY_I2H_QUERY_RSP: - status = be32_to_cpu(m.query->status); - bfa_trc(phy, status); - - if (status == BFA_STATUS_OK) { - struct bfa_phy_attr_s *attr = - (struct bfa_phy_attr_s *) phy->ubuf; - bfa_phy_ntoh32((u32 *)attr, (u32 *)phy->dbuf_kva, - sizeof(struct bfa_phy_attr_s)); - bfa_trc(phy, attr->status); - bfa_trc(phy, attr->length); - } - - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - break; - case BFI_PHY_I2H_STATS_RSP: - status = be32_to_cpu(m.stats->status); - bfa_trc(phy, status); - - if (status == BFA_STATUS_OK) { - struct bfa_phy_stats_s *stats = - (struct bfa_phy_stats_s *) phy->ubuf; - bfa_phy_ntoh32((u32 *)stats, (u32 *)phy->dbuf_kva, - sizeof(struct bfa_phy_stats_s)); - bfa_trc(phy, stats->status); - } - - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - break; - case BFI_PHY_I2H_WRITE_RSP: - status = be32_to_cpu(m.write->status); - bfa_trc(phy, status); - - if (status != BFA_STATUS_OK || phy->residue == 0) { - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - } else { - bfa_trc(phy, phy->offset); - bfa_phy_write_send(phy); - } - break; - case BFI_PHY_I2H_READ_RSP: - status = be32_to_cpu(m.read->status); - bfa_trc(phy, status); - - if (status != BFA_STATUS_OK) { - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - } else { - u32 len = be32_to_cpu(m.read->length); - u16 *buf = (u16 *)(phy->ubuf + phy->offset); - u16 *dbuf = (u16 *)phy->dbuf_kva; - int i, sz = len >> 1; - - bfa_trc(phy, phy->offset); - bfa_trc(phy, len); - - for (i = 0; i < sz; i++) - buf[i] = be16_to_cpu(dbuf[i]); - - phy->residue -= len; - phy->offset += len; - - if (phy->residue == 0) { - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - } else - bfa_phy_read_send(phy); - } - break; - default: - WARN_ON(1); - } -} diff --git a/trunk/drivers/scsi/bfa/bfa_ioc.h b/trunk/drivers/scsi/bfa/bfa_ioc.h index c5ecd2edc95d..c85182a704fb 100644 --- a/trunk/drivers/scsi/bfa/bfa_ioc.h +++ b/trunk/drivers/scsi/bfa/bfa_ioc.h @@ -84,68 +84,6 @@ struct bfa_sge_s { #define bfa_sgaddr_le(_x) (_x) #endif -/* - * BFA memory resources - */ -struct bfa_mem_dma_s { - struct list_head qe; /* Queue of DMA elements */ - u32 mem_len; /* Total Length in Bytes */ - u8 *kva; /* kernel virtual address */ - u64 dma; /* dma address if DMA memory */ - u8 *kva_curp; /* kva allocation cursor */ - u64 dma_curp; /* dma allocation cursor */ -}; -#define bfa_mem_dma_t struct bfa_mem_dma_s - -struct bfa_mem_kva_s { - struct list_head qe; /* Queue of KVA elements */ - u32 mem_len; /* Total Length in Bytes */ - u8 *kva; /* kernel virtual address */ - u8 *kva_curp; /* kva allocation cursor */ -}; -#define bfa_mem_kva_t struct bfa_mem_kva_s - -struct bfa_meminfo_s { - struct bfa_mem_dma_s dma_info; - struct bfa_mem_kva_s kva_info; -}; - -/* BFA memory segment setup macros */ -#define bfa_mem_dma_setup(_meminfo, _dm_ptr, _seg_sz) do { \ - ((bfa_mem_dma_t *)(_dm_ptr))->mem_len = (_seg_sz); \ - if (_seg_sz) \ - list_add_tail(&((bfa_mem_dma_t *)_dm_ptr)->qe, \ - &(_meminfo)->dma_info.qe); \ -} while (0) - -#define bfa_mem_kva_setup(_meminfo, _kva_ptr, _seg_sz) do { \ - ((bfa_mem_kva_t *)(_kva_ptr))->mem_len = (_seg_sz); \ - if (_seg_sz) \ - list_add_tail(&((bfa_mem_kva_t *)_kva_ptr)->qe, \ - &(_meminfo)->kva_info.qe); \ -} while (0) - -/* BFA dma memory segments iterator */ -#define bfa_mem_dma_sptr(_mod, _i) (&(_mod)->dma_seg[(_i)]) -#define bfa_mem_dma_seg_iter(_mod, _sptr, _nr, _i) \ - for (_i = 0, _sptr = bfa_mem_dma_sptr(_mod, _i); _i < (_nr); \ - _i++, _sptr = bfa_mem_dma_sptr(_mod, _i)) - -#define bfa_mem_kva_curp(_mod) ((_mod)->kva_seg.kva_curp) -#define bfa_mem_dma_virt(_sptr) ((_sptr)->kva_curp) -#define bfa_mem_dma_phys(_sptr) ((_sptr)->dma_curp) -#define bfa_mem_dma_len(_sptr) ((_sptr)->mem_len) - -/* Get the corresponding dma buf kva for a req - from the tag */ -#define bfa_mem_get_dmabuf_kva(_mod, _tag, _rqsz) \ - (((u8 *)(_mod)->dma_seg[BFI_MEM_SEG_FROM_TAG(_tag, _rqsz)].kva_curp) +\ - BFI_MEM_SEG_REQ_OFFSET(_tag, _rqsz) * (_rqsz)) - -/* Get the corresponding dma buf pa for a req - from the tag */ -#define bfa_mem_get_dmabuf_pa(_mod, _tag, _rqsz) \ - ((_mod)->dma_seg[BFI_MEM_SEG_FROM_TAG(_tag, _rqsz)].dma_curp + \ - BFI_MEM_SEG_REQ_OFFSET(_tag, _rqsz) * (_rqsz)) - /* * PCI device information required by IOC */ @@ -153,7 +91,6 @@ struct bfa_pcidev_s { int pci_slot; u8 pci_func; u16 device_id; - u16 ssid; void __iomem *pci_bar_kva; }; @@ -175,23 +112,25 @@ struct bfa_dma_s { #define BFI_SMEM_CB_SIZE 0x200000U /* ! 2MB for crossbow */ #define BFI_SMEM_CT_SIZE 0x280000U /* ! 2.5MB for catapult */ -#define bfa_dma_be_addr_set(dma_addr, pa) \ - __bfa_dma_be_addr_set(&dma_addr, (u64)pa) + +#define bfa_dma_addr_set(dma_addr, pa) \ + __bfa_dma_addr_set(&dma_addr, (u64)pa) + static inline void -__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa) +__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa) { - dma_addr->a32.addr_lo = cpu_to_be32(pa); - dma_addr->a32.addr_hi = cpu_to_be32(pa >> 32); + dma_addr->a32.addr_lo = (__be32) pa; + dma_addr->a32.addr_hi = (__be32) (pa >> 32); } -#define bfa_alen_set(__alen, __len, __pa) \ - __bfa_alen_set(__alen, __len, (u64)__pa) +#define bfa_dma_be_addr_set(dma_addr, pa) \ + __bfa_dma_be_addr_set(&dma_addr, (u64)pa) static inline void -__bfa_alen_set(struct bfi_alen_s *alen, u32 len, u64 pa) +__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa) { - alen->al_len = cpu_to_be32(len); - bfa_dma_be_addr_set(alen->al_addr, pa); + dma_addr->a32.addr_lo = cpu_to_be32(pa); + dma_addr->a32.addr_hi = cpu_to_be32(pa >> 32); } struct bfa_ioc_regs_s { @@ -199,7 +138,6 @@ struct bfa_ioc_regs_s { void __iomem *hfn_mbox; void __iomem *lpu_mbox_cmd; void __iomem *lpu_mbox; - void __iomem *lpu_read_stat; void __iomem *pss_ctl_reg; void __iomem *pss_err_status_reg; void __iomem *app_pll_fast_ctl_reg; @@ -261,26 +199,18 @@ struct bfa_ioc_cbfn_s { }; /* - * IOC event notification mechanism. + * Heartbeat failure notification queue element. */ -enum bfa_ioc_event_e { - BFA_IOC_E_ENABLED = 1, - BFA_IOC_E_DISABLED = 2, - BFA_IOC_E_FAILED = 3, -}; - -typedef void (*bfa_ioc_notify_cbfn_t)(void *, enum bfa_ioc_event_e); - -struct bfa_ioc_notify_s { +struct bfa_ioc_hbfail_notify_s { struct list_head qe; - bfa_ioc_notify_cbfn_t cbfn; + bfa_ioc_hbfail_cbfn_t cbfn; void *cbarg; }; /* - * Initialize a IOC event notification structure + * Initialize a heartbeat failure notification structure */ -#define bfa_ioc_notify_init(__notify, __cbfn, __cbarg) do { \ +#define bfa_ioc_hbfail_init(__notify, __cbfn, __cbarg) do { \ (__notify)->cbfn = (__cbfn); \ (__notify)->cbarg = (__cbarg); \ } while (0) @@ -288,9 +218,8 @@ struct bfa_ioc_notify_s { struct bfa_iocpf_s { bfa_fsm_t fsm; struct bfa_ioc_s *ioc; - bfa_boolean_t fw_mismatch_notified; + u32 retry_count; bfa_boolean_t auto_recover; - u32 poll_time; }; struct bfa_ioc_s { @@ -302,15 +231,17 @@ struct bfa_ioc_s { struct bfa_timer_s sem_timer; struct bfa_timer_s hb_timer; u32 hb_count; - struct list_head notify_q; + struct list_head hb_notify_q; void *dbg_fwsave; int dbg_fwsave_len; bfa_boolean_t dbg_fwsave_once; - enum bfi_pcifn_class clscode; + enum bfi_mclass ioc_mc; struct bfa_ioc_regs_s ioc_regs; struct bfa_trc_mod_s *trcmod; struct bfa_ioc_drv_stats_s stats; bfa_boolean_t fcmode; + bfa_boolean_t ctdev; + bfa_boolean_t cna; bfa_boolean_t pllinit; bfa_boolean_t stats_busy; /* outstanding stats */ u8 port_id; @@ -320,17 +251,10 @@ struct bfa_ioc_s { struct bfa_ioc_mbox_mod_s mbox_mod; struct bfa_ioc_hwif_s *ioc_hwif; struct bfa_iocpf_s iocpf; - enum bfi_asic_gen asic_gen; - enum bfi_asic_mode asic_mode; - enum bfi_port_mode port0_mode; - enum bfi_port_mode port1_mode; - enum bfa_mode_s port_mode; - u8 ad_cap_bm; /* adapter cap bit mask */ - u8 port_mode_cfg; /* config port mode */ }; struct bfa_ioc_hwif_s { - bfa_status_t (*ioc_pll_init) (void __iomem *rb, enum bfi_asic_mode m); + bfa_status_t (*ioc_pll_init) (void __iomem *rb, bfa_boolean_t fcmode); bfa_boolean_t (*ioc_firmware_lock) (struct bfa_ioc_s *ioc); void (*ioc_firmware_unlock) (struct bfa_ioc_s *ioc); void (*ioc_reg_init) (struct bfa_ioc_s *ioc); @@ -344,356 +268,12 @@ struct bfa_ioc_hwif_s { void (*ioc_sync_leave) (struct bfa_ioc_s *ioc); void (*ioc_sync_ack) (struct bfa_ioc_s *ioc); bfa_boolean_t (*ioc_sync_complete) (struct bfa_ioc_s *ioc); - bfa_boolean_t (*ioc_lpu_read_stat) (struct bfa_ioc_s *ioc); -}; - -/* - * Queue element to wait for room in request queue. FIFO order is - * maintained when fullfilling requests. - */ -struct bfa_reqq_wait_s { - struct list_head qe; - void (*qresume) (void *cbarg); - void *cbarg; -}; - -typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); - -/* - * Generic BFA callback element. - */ -struct bfa_cb_qe_s { - struct list_head qe; - bfa_cb_cbfn_t cbfn; - bfa_boolean_t once; - void *cbarg; -}; - -/* - * ASIC block configurtion related - */ - -typedef void (*bfa_ablk_cbfn_t)(void *, enum bfa_status); - -struct bfa_ablk_s { - struct bfa_ioc_s *ioc; - struct bfa_ablk_cfg_s *cfg; - u16 *pcifn; - struct bfa_dma_s dma_addr; - bfa_boolean_t busy; - struct bfa_mbox_cmd_s mb; - bfa_ablk_cbfn_t cbfn; - void *cbarg; - struct bfa_ioc_notify_s ioc_notify; - struct bfa_mem_dma_s ablk_dma; -}; -#define BFA_MEM_ABLK_DMA(__bfa) (&((__bfa)->modules.ablk.ablk_dma)) - -/* - * SFP module specific - */ -typedef void (*bfa_cb_sfp_t) (void *cbarg, bfa_status_t status); - -struct bfa_sfp_s { - void *dev; - struct bfa_ioc_s *ioc; - struct bfa_trc_mod_s *trcmod; - struct sfp_mem_s *sfpmem; - bfa_cb_sfp_t cbfn; - void *cbarg; - enum bfi_sfp_mem_e memtype; /* mem access type */ - u32 status; - struct bfa_mbox_cmd_s mbcmd; - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ - struct bfa_ioc_notify_s ioc_notify; - enum bfa_defs_sfp_media_e *media; - enum bfa_port_speed portspeed; - bfa_cb_sfp_t state_query_cbfn; - void *state_query_cbarg; - u8 lock; - u8 data_valid; /* data in dbuf is valid */ - u8 state; /* sfp state */ - u8 state_query_lock; - struct bfa_mem_dma_s sfp_dma; - u8 is_elb; /* eloopback */ -}; - -#define BFA_SFP_MOD(__bfa) (&(__bfa)->modules.sfp) -#define BFA_MEM_SFP_DMA(__bfa) (&(BFA_SFP_MOD(__bfa)->sfp_dma)) - -u32 bfa_sfp_meminfo(void); - -void bfa_sfp_attach(struct bfa_sfp_s *sfp, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod); - -void bfa_sfp_memclaim(struct bfa_sfp_s *diag, u8 *dm_kva, u64 dm_pa); -void bfa_sfp_intr(void *bfaarg, struct bfi_mbmsg_s *msg); - -bfa_status_t bfa_sfp_show(struct bfa_sfp_s *sfp, struct sfp_mem_s *sfpmem, - bfa_cb_sfp_t cbfn, void *cbarg); - -bfa_status_t bfa_sfp_media(struct bfa_sfp_s *sfp, - enum bfa_defs_sfp_media_e *media, - bfa_cb_sfp_t cbfn, void *cbarg); - -bfa_status_t bfa_sfp_speed(struct bfa_sfp_s *sfp, - enum bfa_port_speed portspeed, - bfa_cb_sfp_t cbfn, void *cbarg); - -/* - * Flash module specific - */ -typedef void (*bfa_cb_flash_t) (void *cbarg, bfa_status_t status); - -struct bfa_flash_s { - struct bfa_ioc_s *ioc; /* back pointer to ioc */ - struct bfa_trc_mod_s *trcmod; - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 op_busy; /* operation busy flag */ - u32 residue; /* residual length */ - u32 offset; /* offset */ - bfa_status_t status; /* status */ - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - bfa_cb_flash_t cbfn; /* user callback function */ - void *cbarg; /* user callback arg */ - u8 *ubuf; /* user supplied buffer */ - struct bfa_cb_qe_s hcb_qe; /* comp: BFA callback qelem */ - u32 addr_off; /* partition address offset */ - struct bfa_mbox_cmd_s mb; /* mailbox */ - struct bfa_ioc_notify_s ioc_notify; /* ioc event notify */ - struct bfa_mem_dma_s flash_dma; -}; - -#define BFA_FLASH(__bfa) (&(__bfa)->modules.flash) -#define BFA_MEM_FLASH_DMA(__bfa) (&(BFA_FLASH(__bfa)->flash_dma)) - -bfa_status_t bfa_flash_get_attr(struct bfa_flash_s *flash, - struct bfa_flash_attr_s *attr, - bfa_cb_flash_t cbfn, void *cbarg); -bfa_status_t bfa_flash_erase_part(struct bfa_flash_s *flash, - enum bfa_flash_part_type type, u8 instance, - bfa_cb_flash_t cbfn, void *cbarg); -bfa_status_t bfa_flash_update_part(struct bfa_flash_s *flash, - enum bfa_flash_part_type type, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_flash_t cbfn, void *cbarg); -bfa_status_t bfa_flash_read_part(struct bfa_flash_s *flash, - enum bfa_flash_part_type type, u8 instance, void *buf, - u32 len, u32 offset, bfa_cb_flash_t cbfn, void *cbarg); -u32 bfa_flash_meminfo(bfa_boolean_t mincfg); -void bfa_flash_attach(struct bfa_flash_s *flash, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg); -void bfa_flash_memclaim(struct bfa_flash_s *flash, - u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg); - -/* - * DIAG module specific - */ - -typedef void (*bfa_cb_diag_t) (void *cbarg, bfa_status_t status); -typedef void (*bfa_cb_diag_beacon_t) (void *dev, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon); - -/* - * Firmware ping test results - */ -struct bfa_diag_results_fwping { - u32 data; /* store the corrupted data */ - u32 status; - u32 dmastatus; - u8 rsvd[4]; -}; - -struct bfa_diag_qtest_result_s { - u32 status; - u16 count; /* sucessful queue test count */ - u8 queue; - u8 rsvd; /* 64-bit align */ -}; - -/* - * Firmware ping test results - */ -struct bfa_diag_fwping_s { - struct bfa_diag_results_fwping *result; - bfa_cb_diag_t cbfn; - void *cbarg; - u32 data; - u8 lock; - u8 rsv[3]; - u32 status; - u32 count; - struct bfa_mbox_cmd_s mbcmd; - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ -}; - -/* - * Temperature sensor query results - */ -struct bfa_diag_results_tempsensor_s { - u32 status; - u16 temp; /* 10-bit A/D value */ - u16 brd_temp; /* 9-bit board temp */ - u8 ts_junc; /* show junction tempsensor */ - u8 ts_brd; /* show board tempsensor */ - u8 rsvd[6]; /* keep 8 bytes alignment */ -}; - -struct bfa_diag_tsensor_s { - bfa_cb_diag_t cbfn; - void *cbarg; - struct bfa_diag_results_tempsensor_s *temp; - u8 lock; - u8 rsv[3]; - u32 status; - struct bfa_mbox_cmd_s mbcmd; }; -struct bfa_diag_sfpshow_s { - struct sfp_mem_s *sfpmem; - bfa_cb_diag_t cbfn; - void *cbarg; - u8 lock; - u8 static_data; - u8 rsv[2]; - u32 status; - struct bfa_mbox_cmd_s mbcmd; - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ -}; - -struct bfa_diag_led_s { - struct bfa_mbox_cmd_s mbcmd; - bfa_boolean_t lock; /* 1: ledtest is operating */ -}; - -struct bfa_diag_beacon_s { - struct bfa_mbox_cmd_s mbcmd; - bfa_boolean_t state; /* port beacon state */ - bfa_boolean_t link_e2e; /* link beacon state */ -}; - -struct bfa_diag_s { - void *dev; - struct bfa_ioc_s *ioc; - struct bfa_trc_mod_s *trcmod; - struct bfa_diag_fwping_s fwping; - struct bfa_diag_tsensor_s tsensor; - struct bfa_diag_sfpshow_s sfpshow; - struct bfa_diag_led_s ledtest; - struct bfa_diag_beacon_s beacon; - void *result; - struct bfa_timer_s timer; - bfa_cb_diag_beacon_t cbfn_beacon; - bfa_cb_diag_t cbfn; - void *cbarg; - u8 block; - u8 timer_active; - u8 rsvd[2]; - u32 status; - struct bfa_ioc_notify_s ioc_notify; - struct bfa_mem_dma_s diag_dma; -}; - -#define BFA_DIAG_MOD(__bfa) (&(__bfa)->modules.diag_mod) -#define BFA_MEM_DIAG_DMA(__bfa) (&(BFA_DIAG_MOD(__bfa)->diag_dma)) - -u32 bfa_diag_meminfo(void); -void bfa_diag_memclaim(struct bfa_diag_s *diag, u8 *dm_kva, u64 dm_pa); -void bfa_diag_attach(struct bfa_diag_s *diag, struct bfa_ioc_s *ioc, void *dev, - bfa_cb_diag_beacon_t cbfn_beacon, - struct bfa_trc_mod_s *trcmod); -bfa_status_t bfa_diag_reg_read(struct bfa_diag_s *diag, u32 offset, - u32 len, u32 *buf, u32 force); -bfa_status_t bfa_diag_reg_write(struct bfa_diag_s *diag, u32 offset, - u32 len, u32 value, u32 force); -bfa_status_t bfa_diag_tsensor_query(struct bfa_diag_s *diag, - struct bfa_diag_results_tempsensor_s *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_fwping(struct bfa_diag_s *diag, u32 cnt, - u32 pattern, struct bfa_diag_results_fwping *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_sfpshow(struct bfa_diag_s *diag, - struct sfp_mem_s *sfpmem, u8 static_data, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_memtest(struct bfa_diag_s *diag, - struct bfa_diag_memtest_s *memtest, u32 pattern, - struct bfa_diag_memtest_result *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_ledtest(struct bfa_diag_s *diag, - struct bfa_diag_ledtest_s *ledtest); -bfa_status_t bfa_diag_beacon_port(struct bfa_diag_s *diag, - bfa_boolean_t beacon, bfa_boolean_t link_e2e_beacon, - u32 sec); - -/* - * PHY module specific - */ -typedef void (*bfa_cb_phy_t) (void *cbarg, bfa_status_t status); - -struct bfa_phy_s { - struct bfa_ioc_s *ioc; /* back pointer to ioc */ - struct bfa_trc_mod_s *trcmod; /* trace module */ - u8 instance; /* port instance */ - u8 op_busy; /* operation busy flag */ - u8 rsv[2]; - u32 residue; /* residual length */ - u32 offset; /* offset */ - bfa_status_t status; /* status */ - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - bfa_cb_phy_t cbfn; /* user callback function */ - void *cbarg; /* user callback arg */ - u8 *ubuf; /* user supplied buffer */ - struct bfa_cb_qe_s hcb_qe; /* comp: BFA callback qelem */ - u32 addr_off; /* phy address offset */ - struct bfa_mbox_cmd_s mb; /* mailbox */ - struct bfa_ioc_notify_s ioc_notify; /* ioc event notify */ - struct bfa_mem_dma_s phy_dma; -}; - -#define BFA_PHY(__bfa) (&(__bfa)->modules.phy) -#define BFA_MEM_PHY_DMA(__bfa) (&(BFA_PHY(__bfa)->phy_dma)) - -bfa_boolean_t bfa_phy_busy(struct bfa_ioc_s *ioc); -bfa_status_t bfa_phy_get_attr(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_attr_s *attr, - bfa_cb_phy_t cbfn, void *cbarg); -bfa_status_t bfa_phy_get_stats(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_stats_s *stats, - bfa_cb_phy_t cbfn, void *cbarg); -bfa_status_t bfa_phy_update(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg); -bfa_status_t bfa_phy_read(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg); - -u32 bfa_phy_meminfo(bfa_boolean_t mincfg); -void bfa_phy_attach(struct bfa_phy_s *phy, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg); -void bfa_phy_memclaim(struct bfa_phy_s *phy, - u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg); -void bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg); - -/* - * IOC specfic macros - */ #define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func) #define bfa_ioc_devid(__ioc) ((__ioc)->pcidev.device_id) #define bfa_ioc_bar0(__ioc) ((__ioc)->pcidev.pci_bar_kva) #define bfa_ioc_portid(__ioc) ((__ioc)->port_id) -#define bfa_ioc_asic_gen(__ioc) ((__ioc)->asic_gen) -#define bfa_ioc_is_cna(__ioc) \ - ((bfa_ioc_get_type(__ioc) == BFA_IOC_TYPE_FCoE) || \ - (bfa_ioc_get_type(__ioc) == BFA_IOC_TYPE_LL)) #define bfa_ioc_fetch_stats(__ioc, __stats) \ (((__stats)->drv_stats) = (__ioc)->stats) #define bfa_ioc_clr_stats(__ioc) \ @@ -707,9 +287,12 @@ void bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg); #define bfa_ioc_stats(_ioc, _stats) ((_ioc)->stats._stats++) #define BFA_IOC_FWIMG_MINSZ (16 * 1024) -#define BFA_IOC_FW_SMEM_SIZE(__ioc) \ - ((bfa_ioc_asic_gen(__ioc) == BFI_ASIC_GEN_CB) \ - ? BFI_SMEM_CB_SIZE : BFI_SMEM_CT_SIZE) +#define BFA_IOC_FWIMG_TYPE(__ioc) \ + (((__ioc)->ctdev) ? \ + (((__ioc)->fcmode) ? BFI_IMAGE_CT_FC : BFI_IMAGE_CT_CNA) : \ + BFI_IMAGE_CB_FC) +#define BFA_IOC_FW_SMEM_SIZE(__ioc) \ + (((__ioc)->ctdev) ? BFI_SMEM_CT_SIZE : BFI_SMEM_CB_SIZE) #define BFA_IOC_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS) #define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS) #define BFA_IOC_FLASH_CHUNK_ADDR(chunkno) (chunkno * BFI_FLASH_CHUNK_SZ_WORDS) @@ -722,7 +305,7 @@ void bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs); void bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc); void bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len); -bfa_boolean_t bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg); +void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg); void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg); @@ -732,49 +315,40 @@ void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, #define bfa_ioc_pll_init_asic(__ioc) \ ((__ioc)->ioc_hwif->ioc_pll_init((__ioc)->pcidev.pci_bar_kva, \ - (__ioc)->asic_mode)) + (__ioc)->fcmode)) bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc); -bfa_status_t bfa_ioc_cb_pll_init(void __iomem *rb, enum bfi_asic_mode mode); -bfa_status_t bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode mode); -bfa_status_t bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode mode); +bfa_status_t bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode); +bfa_boolean_t bfa_ioc_ct_pll_init_complete(void __iomem *rb); +bfa_status_t bfa_ioc_ct_pll_init(void __iomem *rb, bfa_boolean_t fcmode); -#define bfa_ioc_isr_mode_set(__ioc, __msix) do { \ - if ((__ioc)->ioc_hwif->ioc_isr_mode_set) \ - ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix)); \ -} while (0) +#define bfa_ioc_isr_mode_set(__ioc, __msix) \ + ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix)) #define bfa_ioc_ownership_reset(__ioc) \ ((__ioc)->ioc_hwif->ioc_ownership_reset(__ioc)) -#define bfa_ioc_get_fcmode(__ioc) ((__ioc)->fcmode) -#define bfa_ioc_lpu_read_stat(__ioc) do { \ - if ((__ioc)->ioc_hwif->ioc_lpu_read_stat) \ - ((__ioc)->ioc_hwif->ioc_lpu_read_stat(__ioc)); \ -} while (0) -void bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc); + void bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc); -void bfa_ioc_set_ct2_hwif(struct bfa_ioc_s *ioc); -void bfa_ioc_ct2_poweron(struct bfa_ioc_s *ioc); +void bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc); void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod); void bfa_ioc_auto_recover(bfa_boolean_t auto_recover); void bfa_ioc_detach(struct bfa_ioc_s *ioc); void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, - enum bfi_pcifn_class clscode); + enum bfi_mclass mc); void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa); void bfa_ioc_enable(struct bfa_ioc_s *ioc); void bfa_ioc_disable(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_intx_claim(struct bfa_ioc_s *ioc); void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, - u32 boot_env); + u32 boot_param); void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *msg); void bfa_ioc_error_isr(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_initialized(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc); -bfa_boolean_t bfa_ioc_is_acq_addr(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc); void bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc); @@ -798,6 +372,8 @@ bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen); bfa_status_t bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf, u32 *offset, int *buflen); +void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc); +bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_sem_get(void __iomem *sem_reg); void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr); @@ -806,33 +382,6 @@ bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, bfa_status_t bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats); bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc); -/* - * asic block configuration related APIs - */ -u32 bfa_ablk_meminfo(void); -void bfa_ablk_memclaim(struct bfa_ablk_s *ablk, u8 *dma_kva, u64 dma_pa); -void bfa_ablk_attach(struct bfa_ablk_s *ablk, struct bfa_ioc_s *ioc); -bfa_status_t bfa_ablk_query(struct bfa_ablk_s *ablk, - struct bfa_ablk_cfg_s *ablk_cfg, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_adapter_config(struct bfa_ablk_s *ablk, - enum bfa_mode_s mode, int max_pf, int max_vf, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_port_config(struct bfa_ablk_s *ablk, int port, - enum bfa_mode_s mode, int max_pf, int max_vf, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_pf_create(struct bfa_ablk_s *ablk, u16 *pcifn, - u8 port, enum bfi_pcifn_class personality, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_pf_delete(struct bfa_ablk_s *ablk, int pcifn, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_optrom_en(struct bfa_ablk_s *ablk, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_optrom_dis(struct bfa_ablk_s *ablk, - bfa_ablk_cbfn_t cbfn, void *cbarg); - /* * bfa mfg wwn API functions */ @@ -842,64 +391,50 @@ mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc); /* * F/W Image Size & Chunk */ -extern u32 bfi_image_cb_size; -extern u32 bfi_image_ct_size; -extern u32 bfi_image_ct2_size; -extern u32 *bfi_image_cb; -extern u32 *bfi_image_ct; -extern u32 *bfi_image_ct2; +extern u32 bfi_image_ct_fc_size; +extern u32 bfi_image_ct_cna_size; +extern u32 bfi_image_cb_fc_size; +extern u32 *bfi_image_ct_fc; +extern u32 *bfi_image_ct_cna; +extern u32 *bfi_image_cb_fc; static inline u32 * -bfi_image_cb_get_chunk(u32 off) -{ - return (u32 *)(bfi_image_cb + off); -} +bfi_image_ct_fc_get_chunk(u32 off) +{ return (u32 *)(bfi_image_ct_fc + off); } static inline u32 * -bfi_image_ct_get_chunk(u32 off) -{ - return (u32 *)(bfi_image_ct + off); -} +bfi_image_ct_cna_get_chunk(u32 off) +{ return (u32 *)(bfi_image_ct_cna + off); } static inline u32 * -bfi_image_ct2_get_chunk(u32 off) -{ - return (u32 *)(bfi_image_ct2 + off); -} +bfi_image_cb_fc_get_chunk(u32 off) +{ return (u32 *)(bfi_image_cb_fc + off); } static inline u32* -bfa_cb_image_get_chunk(enum bfi_asic_gen asic_gen, u32 off) +bfa_cb_image_get_chunk(int type, u32 off) { - switch (asic_gen) { - case BFI_ASIC_GEN_CB: - return bfi_image_cb_get_chunk(off); - break; - case BFI_ASIC_GEN_CT: - return bfi_image_ct_get_chunk(off); - break; - case BFI_ASIC_GEN_CT2: - return bfi_image_ct2_get_chunk(off); - break; - default: - return NULL; + switch (type) { + case BFI_IMAGE_CT_FC: + return bfi_image_ct_fc_get_chunk(off); break; + case BFI_IMAGE_CT_CNA: + return bfi_image_ct_cna_get_chunk(off); break; + case BFI_IMAGE_CB_FC: + return bfi_image_cb_fc_get_chunk(off); break; + default: return NULL; } } static inline u32 -bfa_cb_image_get_size(enum bfi_asic_gen asic_gen) +bfa_cb_image_get_size(int type) { - switch (asic_gen) { - case BFI_ASIC_GEN_CB: - return bfi_image_cb_size; - break; - case BFI_ASIC_GEN_CT: - return bfi_image_ct_size; - break; - case BFI_ASIC_GEN_CT2: - return bfi_image_ct2_size; - break; - default: - return 0; + switch (type) { + case BFI_IMAGE_CT_FC: + return bfi_image_ct_fc_size; break; + case BFI_IMAGE_CT_CNA: + return bfi_image_ct_cna_size; break; + case BFI_IMAGE_CB_FC: + return bfi_image_cb_fc_size; break; + default: return 0; } } diff --git a/trunk/drivers/scsi/bfa/bfa_ioc_cb.c b/trunk/drivers/scsi/bfa/bfa_ioc_cb.c index 30df8a284715..89ae4c8f95a2 100644 --- a/trunk/drivers/scsi/bfa/bfa_ioc_cb.c +++ b/trunk/drivers/scsi/bfa/bfa_ioc_cb.c @@ -17,7 +17,7 @@ #include "bfad_drv.h" #include "bfa_ioc.h" -#include "bfi_reg.h" +#include "bfi_cbreg.h" #include "bfa_defs.h" BFA_TRC_FILE(CNA, IOC_CB); @@ -69,6 +69,21 @@ bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc) static bfa_boolean_t bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc) { + struct bfi_ioc_image_hdr_s fwhdr; + uint32_t fwstate = readl(ioc->ioc_regs.ioc_fwstate); + + if (fwstate == BFI_IOC_UNINIT) + return BFA_TRUE; + + bfa_ioc_fwver_get(ioc, &fwhdr); + + if (swab32(fwhdr.exec) == BFI_BOOT_TYPE_NORMAL) + return BFA_TRUE; + + bfa_trc(ioc, fwstate); + bfa_trc(ioc, fwhdr.exec); + writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate); + return BFA_TRUE; } @@ -83,7 +98,7 @@ bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc) static void bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc) { - writel(~0U, ioc->ioc_regs.err_set); + writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set); readl(ioc->ioc_regs.err_set); } @@ -137,8 +152,8 @@ bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc) */ ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); - ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_LCLK_CTL_REG); - ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_SCLK_CTL_REG); + ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_400_CTL_REG); + ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_212_CTL_REG); /* * IOC semaphore registers and serialization @@ -270,18 +285,18 @@ bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc) } bfa_status_t -bfa_ioc_cb_pll_init(void __iomem *rb, enum bfi_asic_mode fcmode) +bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode) { u32 pll_sclk, pll_fclk; - pll_sclk = __APP_PLL_SCLK_ENABLE | __APP_PLL_SCLK_LRESETN | - __APP_PLL_SCLK_P0_1(3U) | - __APP_PLL_SCLK_JITLMT0_1(3U) | - __APP_PLL_SCLK_CNTLMT0_1(3U); - pll_fclk = __APP_PLL_LCLK_ENABLE | __APP_PLL_LCLK_LRESETN | - __APP_PLL_LCLK_RSEL200500 | __APP_PLL_LCLK_P0_1(3U) | - __APP_PLL_LCLK_JITLMT0_1(3U) | - __APP_PLL_LCLK_CNTLMT0_1(3U); + pll_sclk = __APP_PLL_212_ENABLE | __APP_PLL_212_LRESETN | + __APP_PLL_212_P0_1(3U) | + __APP_PLL_212_JITLMT0_1(3U) | + __APP_PLL_212_CNTLMT0_1(3U); + pll_fclk = __APP_PLL_400_ENABLE | __APP_PLL_400_LRESETN | + __APP_PLL_400_RSEL200500 | __APP_PLL_400_P0_1(3U) | + __APP_PLL_400_JITLMT0_1(3U) | + __APP_PLL_400_CNTLMT0_1(3U); writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG)); writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG)); writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); @@ -290,24 +305,24 @@ bfa_ioc_cb_pll_init(void __iomem *rb, enum bfi_asic_mode fcmode) writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); writel(0xffffffffU, (rb + HOSTFN1_INT_MSK)); - writel(__APP_PLL_SCLK_LOGIC_SOFT_RESET, rb + APP_PLL_SCLK_CTL_REG); - writel(__APP_PLL_SCLK_BYPASS | __APP_PLL_SCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_SCLK_CTL_REG); - writel(__APP_PLL_LCLK_LOGIC_SOFT_RESET, rb + APP_PLL_LCLK_CTL_REG); - writel(__APP_PLL_LCLK_BYPASS | __APP_PLL_LCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_LCLK_CTL_REG); + writel(__APP_PLL_212_LOGIC_SOFT_RESET, rb + APP_PLL_212_CTL_REG); + writel(__APP_PLL_212_BYPASS | __APP_PLL_212_LOGIC_SOFT_RESET, + rb + APP_PLL_212_CTL_REG); + writel(__APP_PLL_400_LOGIC_SOFT_RESET, rb + APP_PLL_400_CTL_REG); + writel(__APP_PLL_400_BYPASS | __APP_PLL_400_LOGIC_SOFT_RESET, + rb + APP_PLL_400_CTL_REG); udelay(2); - writel(__APP_PLL_SCLK_LOGIC_SOFT_RESET, rb + APP_PLL_SCLK_CTL_REG); - writel(__APP_PLL_LCLK_LOGIC_SOFT_RESET, rb + APP_PLL_LCLK_CTL_REG); - writel(pll_sclk | __APP_PLL_SCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_LCLK_CTL_REG); + writel(__APP_PLL_212_LOGIC_SOFT_RESET, rb + APP_PLL_212_CTL_REG); + writel(__APP_PLL_400_LOGIC_SOFT_RESET, rb + APP_PLL_400_CTL_REG); + writel(pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET, + rb + APP_PLL_212_CTL_REG); + writel(pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET, + rb + APP_PLL_400_CTL_REG); udelay(2000); writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS)); writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); - writel(pll_sclk, (rb + APP_PLL_SCLK_CTL_REG)); - writel(pll_fclk, (rb + APP_PLL_LCLK_CTL_REG)); + writel(pll_sclk, (rb + APP_PLL_212_CTL_REG)); + writel(pll_fclk, (rb + APP_PLL_400_CTL_REG)); return BFA_STATUS_OK; } diff --git a/trunk/drivers/scsi/bfa/bfa_ioc_ct.c b/trunk/drivers/scsi/bfa/bfa_ioc_ct.c index d1b8f0caaa79..93612520f0d2 100644 --- a/trunk/drivers/scsi/bfa/bfa_ioc_ct.c +++ b/trunk/drivers/scsi/bfa/bfa_ioc_ct.c @@ -17,7 +17,7 @@ #include "bfad_drv.h" #include "bfa_ioc.h" -#include "bfi_reg.h" +#include "bfi_ctreg.h" #include "bfa_defs.h" BFA_TRC_FILE(CNA, IOC_CT); @@ -36,6 +36,9 @@ BFA_TRC_FILE(CNA, IOC_CT); */ static bfa_boolean_t bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc); static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc); +static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc); +static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc); +static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc); static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc); static bfa_boolean_t bfa_ioc_ct_sync_start(struct bfa_ioc_s *ioc); @@ -45,7 +48,29 @@ static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc); static bfa_boolean_t bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc); static struct bfa_ioc_hwif_s hwif_ct; -static struct bfa_ioc_hwif_s hwif_ct2; + +/* + * Called from bfa_ioc_attach() to map asic specific calls. + */ +void +bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc) +{ + hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init; + hwif_ct.ioc_firmware_lock = bfa_ioc_ct_firmware_lock; + hwif_ct.ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock; + hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init; + hwif_ct.ioc_map_port = bfa_ioc_ct_map_port; + hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; + hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail; + hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; + hwif_ct.ioc_sync_start = bfa_ioc_ct_sync_start; + hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join; + hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave; + hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack; + hwif_ct.ioc_sync_complete = bfa_ioc_ct_sync_complete; + + ioc->ioc_hwif = &hwif_ct; +} /* * Return true if firmware of current driver matches the running firmware. @@ -57,10 +82,16 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) u32 usecnt; struct bfi_ioc_image_hdr_s fwhdr; + /* + * Firmware match check is relevant only for CNA. + */ + if (!ioc->cna) + return BFA_TRUE; + /* * If bios boot (flash based) -- do not increment usage count */ - if (bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)) < + if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ) return BFA_TRUE; @@ -72,7 +103,6 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) */ if (usecnt == 0) { writel(1, ioc->ioc_regs.ioc_usage_reg); - readl(ioc->ioc_regs.ioc_usage_sem_reg); writel(1, ioc->ioc_regs.ioc_usage_sem_reg); writel(0, ioc->ioc_regs.ioc_fail_sync); bfa_trc(ioc, usecnt); @@ -92,7 +122,6 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) */ bfa_ioc_fwver_get(ioc, &fwhdr); if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) { - readl(ioc->ioc_regs.ioc_usage_sem_reg); writel(1, ioc->ioc_regs.ioc_usage_sem_reg); bfa_trc(ioc, usecnt); return BFA_FALSE; @@ -103,7 +132,6 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) */ usecnt++; writel(usecnt, ioc->ioc_regs.ioc_usage_reg); - readl(ioc->ioc_regs.ioc_usage_sem_reg); writel(1, ioc->ioc_regs.ioc_usage_sem_reg); bfa_trc(ioc, usecnt); return BFA_TRUE; @@ -114,10 +142,16 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) { u32 usecnt; + /* + * Firmware lock is relevant only for CNA. + */ + if (!ioc->cna) + return; + /* * If bios boot (flash based) -- do not decrement usage count */ - if (bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)) < + if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ) return; @@ -132,7 +166,6 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) writel(usecnt, ioc->ioc_regs.ioc_usage_reg); bfa_trc(ioc, usecnt); - readl(ioc->ioc_regs.ioc_usage_sem_reg); writel(1, ioc->ioc_regs.ioc_usage_sem_reg); } @@ -142,14 +175,14 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc) { - if (bfa_ioc_is_cna(ioc)) { + if (ioc->cna) { writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt); writel(__FW_INIT_HALT_P, ioc->ioc_regs.alt_ll_halt); /* Wait for halt to take effect */ readl(ioc->ioc_regs.ll_halt); readl(ioc->ioc_regs.alt_ll_halt); } else { - writel(~0U, ioc->ioc_regs.err_set); + writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set); readl(ioc->ioc_regs.err_set); } } @@ -157,7 +190,7 @@ bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc) /* * Host to LPU mailbox message addresses */ -static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } ct_fnreg[] = { +static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = { { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 }, { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 }, { HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 }, @@ -167,31 +200,21 @@ static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } ct_fnreg[] = { /* * Host <-> LPU mailbox command/status registers - port 0 */ -static struct { u32 hfn, lpu; } ct_p0reg[] = { - { HOSTFN0_LPU0_CMD_STAT, LPU0_HOSTFN0_CMD_STAT }, - { HOSTFN1_LPU0_CMD_STAT, LPU0_HOSTFN1_CMD_STAT }, - { HOSTFN2_LPU0_CMD_STAT, LPU0_HOSTFN2_CMD_STAT }, - { HOSTFN3_LPU0_CMD_STAT, LPU0_HOSTFN3_CMD_STAT } +static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = { + { HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT }, + { HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT }, + { HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT }, + { HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT } }; /* * Host <-> LPU mailbox command/status registers - port 1 */ -static struct { u32 hfn, lpu; } ct_p1reg[] = { - { HOSTFN0_LPU1_CMD_STAT, LPU1_HOSTFN0_CMD_STAT }, - { HOSTFN1_LPU1_CMD_STAT, LPU1_HOSTFN1_CMD_STAT }, - { HOSTFN2_LPU1_CMD_STAT, LPU1_HOSTFN2_CMD_STAT }, - { HOSTFN3_LPU1_CMD_STAT, LPU1_HOSTFN3_CMD_STAT } -}; - -static struct { uint32_t hfn_mbox, lpu_mbox, hfn_pgn, hfn, lpu, lpu_read; } - ct2_reg[] = { - { CT2_HOSTFN_LPU0_MBOX0, CT2_LPU0_HOSTFN_MBOX0, CT2_HOSTFN_PAGE_NUM, - CT2_HOSTFN_LPU0_CMD_STAT, CT2_LPU0_HOSTFN_CMD_STAT, - CT2_HOSTFN_LPU0_READ_STAT}, - { CT2_HOSTFN_LPU1_MBOX0, CT2_LPU1_HOSTFN_MBOX0, CT2_HOSTFN_PAGE_NUM, - CT2_HOSTFN_LPU1_CMD_STAT, CT2_LPU1_HOSTFN_CMD_STAT, - CT2_HOSTFN_LPU1_READ_STAT}, +static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = { + { HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT }, + { HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT }, + { HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT }, + { HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT } }; static void @@ -202,24 +225,24 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) rb = bfa_ioc_bar0(ioc); - ioc->ioc_regs.hfn_mbox = rb + ct_fnreg[pcifn].hfn_mbox; - ioc->ioc_regs.lpu_mbox = rb + ct_fnreg[pcifn].lpu_mbox; - ioc->ioc_regs.host_page_num_fn = rb + ct_fnreg[pcifn].hfn_pgn; + ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox; + ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox; + ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn; if (ioc->port_id == 0) { ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG; - ioc->ioc_regs.hfn_mbox_cmd = rb + ct_p0reg[pcifn].hfn; - ioc->ioc_regs.lpu_mbox_cmd = rb + ct_p0reg[pcifn].lpu; + ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn; + ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu; ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1; } else { ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC0_STATE_REG; - ioc->ioc_regs.hfn_mbox_cmd = rb + ct_p1reg[pcifn].hfn; - ioc->ioc_regs.lpu_mbox_cmd = rb + ct_p1reg[pcifn].lpu; + ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn; + ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu; ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0; } @@ -229,8 +252,8 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) */ ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); - ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_LCLK_CTL_REG); - ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_SCLK_CTL_REG); + ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG); + ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG); /* * IOC semaphore registers and serialization @@ -253,64 +276,6 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) ioc->ioc_regs.err_set = (rb + ERR_SET_REG); } -static void -bfa_ioc_ct2_reg_init(struct bfa_ioc_s *ioc) -{ - void __iomem *rb; - int port = bfa_ioc_portid(ioc); - - rb = bfa_ioc_bar0(ioc); - - ioc->ioc_regs.hfn_mbox = rb + ct2_reg[port].hfn_mbox; - ioc->ioc_regs.lpu_mbox = rb + ct2_reg[port].lpu_mbox; - ioc->ioc_regs.host_page_num_fn = rb + ct2_reg[port].hfn_pgn; - ioc->ioc_regs.hfn_mbox_cmd = rb + ct2_reg[port].hfn; - ioc->ioc_regs.lpu_mbox_cmd = rb + ct2_reg[port].lpu; - ioc->ioc_regs.lpu_read_stat = rb + ct2_reg[port].lpu_read; - - if (port == 0) { - ioc->ioc_regs.heartbeat = rb + CT2_BFA_IOC0_HBEAT_REG; - ioc->ioc_regs.ioc_fwstate = rb + CT2_BFA_IOC0_STATE_REG; - ioc->ioc_regs.alt_ioc_fwstate = rb + CT2_BFA_IOC1_STATE_REG; - ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; - ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1; - } else { - ioc->ioc_regs.heartbeat = (rb + CT2_BFA_IOC1_HBEAT_REG); - ioc->ioc_regs.ioc_fwstate = (rb + CT2_BFA_IOC1_STATE_REG); - ioc->ioc_regs.alt_ioc_fwstate = rb + CT2_BFA_IOC0_STATE_REG; - ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; - ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0; - } - - /* - * PSS control registers - */ - ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); - ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); - ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + CT2_APP_PLL_LCLK_CTL_REG); - ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + CT2_APP_PLL_SCLK_CTL_REG); - - /* - * IOC semaphore registers and serialization - */ - ioc->ioc_regs.ioc_sem_reg = (rb + CT2_HOST_SEM0_REG); - ioc->ioc_regs.ioc_usage_sem_reg = (rb + CT2_HOST_SEM1_REG); - ioc->ioc_regs.ioc_init_sem_reg = (rb + CT2_HOST_SEM2_REG); - ioc->ioc_regs.ioc_usage_reg = (rb + CT2_BFA_FW_USE_COUNT); - ioc->ioc_regs.ioc_fail_sync = (rb + CT2_BFA_IOC_FAIL_SYNC); - - /* - * sram memory access - */ - ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START); - ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT; - - /* - * err set reg : for notification of hb failure in fcmode - */ - ioc->ioc_regs.err_set = (rb + ERR_SET_REG); -} - /* * Initialize IOC to port mapping. */ @@ -333,19 +298,6 @@ bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc) bfa_trc(ioc, ioc->port_id); } -static void -bfa_ioc_ct2_map_port(struct bfa_ioc_s *ioc) -{ - void __iomem *rb = ioc->pcidev.pci_bar_kva; - u32 r32; - - r32 = readl(rb + CT2_HOSTFN_PERSONALITY0); - ioc->port_id = ((r32 & __FC_LL_PORT_MAP__MK) >> __FC_LL_PORT_MAP__SH); - - bfa_trc(ioc, bfa_ioc_pcifn(ioc)); - bfa_trc(ioc, ioc->port_id); -} - /* * Set interrupt mode for a function: INTX or MSIX */ @@ -364,7 +316,7 @@ bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) /* * If already in desired mode, do not change anything */ - if ((!msix && mode) || (msix && !mode)) + if (!msix && mode) return; if (msix) @@ -379,20 +331,6 @@ bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) writel(r32, rb + FNC_PERS_REG); } -bfa_boolean_t -bfa_ioc_ct2_lpu_read_stat(struct bfa_ioc_s *ioc) -{ - u32 r32; - - r32 = readl(ioc->ioc_regs.lpu_read_stat); - if (r32) { - writel(1, ioc->ioc_regs.lpu_read_stat); - return BFA_TRUE; - } - - return BFA_FALSE; -} - /* * Cleanup hw semaphore and usecnt registers */ @@ -400,10 +338,9 @@ static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc) { - if (bfa_ioc_is_cna(ioc)) { + if (ioc->cna) { bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); writel(0, ioc->ioc_regs.ioc_usage_reg); - readl(ioc->ioc_regs.ioc_usage_sem_reg); writel(1, ioc->ioc_regs.ioc_usage_sem_reg); } @@ -512,99 +449,32 @@ bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc) return BFA_FALSE; } -/** - * Called from bfa_ioc_attach() to map asic specific calls. - */ -static void -bfa_ioc_set_ctx_hwif(struct bfa_ioc_s *ioc, struct bfa_ioc_hwif_s *hwif) -{ - hwif->ioc_firmware_lock = bfa_ioc_ct_firmware_lock; - hwif->ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock; - hwif->ioc_notify_fail = bfa_ioc_ct_notify_fail; - hwif->ioc_ownership_reset = bfa_ioc_ct_ownership_reset; - hwif->ioc_sync_start = bfa_ioc_ct_sync_start; - hwif->ioc_sync_join = bfa_ioc_ct_sync_join; - hwif->ioc_sync_leave = bfa_ioc_ct_sync_leave; - hwif->ioc_sync_ack = bfa_ioc_ct_sync_ack; - hwif->ioc_sync_complete = bfa_ioc_ct_sync_complete; -} - -/** - * Called from bfa_ioc_attach() to map asic specific calls. - */ -void -bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc) -{ - bfa_ioc_set_ctx_hwif(ioc, &hwif_ct); - - hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init; - hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init; - hwif_ct.ioc_map_port = bfa_ioc_ct_map_port; - hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; - ioc->ioc_hwif = &hwif_ct; -} - -/** - * Called from bfa_ioc_attach() to map asic specific calls. - */ -void -bfa_ioc_set_ct2_hwif(struct bfa_ioc_s *ioc) -{ - bfa_ioc_set_ctx_hwif(ioc, &hwif_ct2); - - hwif_ct2.ioc_pll_init = bfa_ioc_ct2_pll_init; - hwif_ct2.ioc_reg_init = bfa_ioc_ct2_reg_init; - hwif_ct2.ioc_map_port = bfa_ioc_ct2_map_port; - hwif_ct2.ioc_lpu_read_stat = bfa_ioc_ct2_lpu_read_stat; - hwif_ct2.ioc_isr_mode_set = NULL; - ioc->ioc_hwif = &hwif_ct2; -} - /* - * Workaround for MSI-X resource allocation for catapult-2 with no asic block + * Check the firmware state to know if pll_init has been completed already */ -#define HOSTFN_MSIX_DEFAULT 64 -#define HOSTFN_MSIX_VT_INDEX_MBOX_ERR 0x30138 -#define HOSTFN_MSIX_VT_OFST_NUMVT 0x3013c -#define __MSIX_VT_NUMVT__MK 0x003ff800 -#define __MSIX_VT_NUMVT__SH 11 -#define __MSIX_VT_NUMVT_(_v) ((_v) << __MSIX_VT_NUMVT__SH) -#define __MSIX_VT_OFST_ 0x000007ff -void -bfa_ioc_ct2_poweron(struct bfa_ioc_s *ioc) +bfa_boolean_t +bfa_ioc_ct_pll_init_complete(void __iomem *rb) { - void __iomem *rb = ioc->pcidev.pci_bar_kva; - u32 r32; - - r32 = readl(rb + HOSTFN_MSIX_VT_OFST_NUMVT); - if (r32 & __MSIX_VT_NUMVT__MK) { - writel(r32 & __MSIX_VT_OFST_, - rb + HOSTFN_MSIX_VT_INDEX_MBOX_ERR); - return; - } + if ((readl(rb + BFA_IOC0_STATE_REG) == BFI_IOC_OP) || + (readl(rb + BFA_IOC1_STATE_REG) == BFI_IOC_OP)) + return BFA_TRUE; - writel(__MSIX_VT_NUMVT_(HOSTFN_MSIX_DEFAULT - 1) | - HOSTFN_MSIX_DEFAULT * bfa_ioc_pcifn(ioc), - rb + HOSTFN_MSIX_VT_OFST_NUMVT); - writel(HOSTFN_MSIX_DEFAULT * bfa_ioc_pcifn(ioc), - rb + HOSTFN_MSIX_VT_INDEX_MBOX_ERR); + return BFA_FALSE; } bfa_status_t -bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode mode) +bfa_ioc_ct_pll_init(void __iomem *rb, bfa_boolean_t fcmode) { u32 pll_sclk, pll_fclk, r32; - bfa_boolean_t fcmode = (mode == BFI_ASIC_MODE_FC); - - pll_sclk = __APP_PLL_SCLK_LRESETN | __APP_PLL_SCLK_ENARST | - __APP_PLL_SCLK_RSEL200500 | __APP_PLL_SCLK_P0_1(3U) | - __APP_PLL_SCLK_JITLMT0_1(3U) | - __APP_PLL_SCLK_CNTLMT0_1(1U); - pll_fclk = __APP_PLL_LCLK_LRESETN | __APP_PLL_LCLK_ENARST | - __APP_PLL_LCLK_RSEL200500 | __APP_PLL_LCLK_P0_1(3U) | - __APP_PLL_LCLK_JITLMT0_1(3U) | - __APP_PLL_LCLK_CNTLMT0_1(1U); + pll_sclk = __APP_PLL_312_LRESETN | __APP_PLL_312_ENARST | + __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(3U) | + __APP_PLL_312_JITLMT0_1(3U) | + __APP_PLL_312_CNTLMT0_1(1U); + pll_fclk = __APP_PLL_425_LRESETN | __APP_PLL_425_ENARST | + __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) | + __APP_PLL_425_JITLMT0_1(3U) | + __APP_PLL_425_CNTLMT0_1(1U); if (fcmode) { writel(0, (rb + OP_MODE)); writel(__APP_EMS_CMLCKSEL | __APP_EMS_REFCKBUFEN2 | @@ -621,21 +491,20 @@ bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode mode) writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); writel(0xffffffffU, (rb + HOSTFN1_INT_MSK)); - writel(pll_sclk | __APP_PLL_SCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_LCLK_CTL_REG); - writel(pll_sclk | __APP_PLL_SCLK_LOGIC_SOFT_RESET | - __APP_PLL_SCLK_ENABLE, rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_LOGIC_SOFT_RESET | - __APP_PLL_LCLK_ENABLE, rb + APP_PLL_LCLK_CTL_REG); + writel(pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET, + rb + APP_PLL_312_CTL_REG); + writel(pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET, + rb + APP_PLL_425_CTL_REG); + writel(pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE, + rb + APP_PLL_312_CTL_REG); + writel(pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE, + rb + APP_PLL_425_CTL_REG); readl(rb + HOSTFN0_INT_MSK); udelay(2000); writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS)); writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); - writel(pll_sclk | __APP_PLL_SCLK_ENABLE, rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_ENABLE, rb + APP_PLL_LCLK_CTL_REG); - + writel(pll_sclk | __APP_PLL_312_ENABLE, rb + APP_PLL_312_CTL_REG); + writel(pll_fclk | __APP_PLL_425_ENABLE, rb + APP_PLL_425_CTL_REG); if (!fcmode) { writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P0)); writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P1)); @@ -655,206 +524,3 @@ bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode mode) writel(0, (rb + MBIST_CTL_REG)); return BFA_STATUS_OK; } - -static void -bfa_ioc_ct2_sclk_init(void __iomem *rb) -{ - u32 r32; - - /* - * put s_clk PLL and PLL FSM in reset - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - r32 &= ~(__APP_PLL_SCLK_ENABLE | __APP_PLL_SCLK_LRESETN); - r32 |= (__APP_PLL_SCLK_ENARST | __APP_PLL_SCLK_BYPASS | - __APP_PLL_SCLK_LOGIC_SOFT_RESET); - writel(r32, (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * Ignore mode and program for the max clock (which is FC16) - * Firmware/NFC will do the PLL init appropiately - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - r32 &= ~(__APP_PLL_SCLK_REFCLK_SEL | __APP_PLL_SCLK_CLK_DIV2); - writel(r32, (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * while doing PLL init dont clock gate ethernet subsystem - */ - r32 = readl((rb + CT2_CHIP_MISC_PRG)); - writel(r32 | __ETH_CLK_ENABLE_PORT0, (rb + CT2_CHIP_MISC_PRG)); - - r32 = readl((rb + CT2_PCIE_MISC_REG)); - writel(r32 | __ETH_CLK_ENABLE_PORT1, (rb + CT2_PCIE_MISC_REG)); - - /* - * set sclk value - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - r32 &= (__P_SCLK_PLL_LOCK | __APP_PLL_SCLK_REFCLK_SEL | - __APP_PLL_SCLK_CLK_DIV2); - writel(r32 | 0x1061731b, (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * poll for s_clk lock or delay 1ms - */ - udelay(1000); -} - -static void -bfa_ioc_ct2_lclk_init(void __iomem *rb) -{ - u32 r32; - - /* - * put l_clk PLL and PLL FSM in reset - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - r32 &= ~(__APP_PLL_LCLK_ENABLE | __APP_PLL_LCLK_LRESETN); - r32 |= (__APP_PLL_LCLK_ENARST | __APP_PLL_LCLK_BYPASS | - __APP_PLL_LCLK_LOGIC_SOFT_RESET); - writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * set LPU speed (set for FC16 which will work for other modes) - */ - r32 = readl((rb + CT2_CHIP_MISC_PRG)); - writel(r32, (rb + CT2_CHIP_MISC_PRG)); - - /* - * set LPU half speed (set for FC16 which will work for other modes) - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * set lclk for mode (set for FC16) - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - r32 &= (__P_LCLK_PLL_LOCK | __APP_LPUCLK_HALFSPEED); - r32 |= 0x20c1731b; - writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * poll for s_clk lock or delay 1ms - */ - udelay(1000); -} - -static void -bfa_ioc_ct2_mem_init(void __iomem *rb) -{ - u32 r32; - - r32 = readl((rb + PSS_CTL_REG)); - r32 &= ~__PSS_LMEM_RESET; - writel(r32, (rb + PSS_CTL_REG)); - udelay(1000); - - writel(__EDRAM_BISTR_START, (rb + CT2_MBIST_CTL_REG)); - udelay(1000); - writel(0, (rb + CT2_MBIST_CTL_REG)); -} - -void -bfa_ioc_ct2_mac_reset(void __iomem *rb) -{ - u32 r32; - - bfa_ioc_ct2_sclk_init(rb); - bfa_ioc_ct2_lclk_init(rb); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* put port0, port1 MAC & AHB in reset */ - writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET), - rb + CT2_CSI_MAC_CONTROL_REG(0)); - writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET), - rb + CT2_CSI_MAC_CONTROL_REG(1)); -} - -#define CT2_NFC_MAX_DELAY 1000 -bfa_status_t -bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode mode) -{ - u32 wgn, r32; - int i; - - /* - * Initialize PLL if not already done by NFC - */ - wgn = readl(rb + CT2_WGN_STATUS); - if (!(wgn & __GLBL_PF_VF_CFG_RDY)) { - writel(__HALT_NFC_CONTROLLER, rb + CT2_NFC_CSR_SET_REG); - for (i = 0; i < CT2_NFC_MAX_DELAY; i++) { - r32 = readl(rb + CT2_NFC_CSR_SET_REG); - if (r32 & __NFC_CONTROLLER_HALTED) - break; - udelay(1000); - } - } - - /* - * Mask the interrupts and clear any - * pending interrupts. - */ - writel(1, (rb + CT2_LPU0_HOSTFN_MBOX0_MSK)); - writel(1, (rb + CT2_LPU1_HOSTFN_MBOX0_MSK)); - - r32 = readl((rb + CT2_LPU0_HOSTFN_CMD_STAT)); - if (r32 == 1) { - writel(1, (rb + CT2_LPU0_HOSTFN_CMD_STAT)); - readl((rb + CT2_LPU0_HOSTFN_CMD_STAT)); - } - r32 = readl((rb + CT2_LPU1_HOSTFN_CMD_STAT)); - if (r32 == 1) { - writel(1, (rb + CT2_LPU1_HOSTFN_CMD_STAT)); - readl((rb + CT2_LPU1_HOSTFN_CMD_STAT)); - } - - bfa_ioc_ct2_mac_reset(rb); - bfa_ioc_ct2_sclk_init(rb); - bfa_ioc_ct2_lclk_init(rb); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * Announce flash device presence, if flash was corrupted. - */ - if (wgn == (__WGN_READY | __GLBL_PF_VF_CFG_RDY)) { - r32 = readl((rb + PSS_GPIO_OUT_REG)); - writel(r32 & ~1, (rb + PSS_GPIO_OUT_REG)); - r32 = readl((rb + PSS_GPIO_OE_REG)); - writel(r32 | 1, (rb + PSS_GPIO_OE_REG)); - } - - bfa_ioc_ct2_mem_init(rb); - - writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC0_STATE_REG)); - writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC1_STATE_REG)); - return BFA_STATUS_OK; -} diff --git a/trunk/drivers/scsi/bfa/bfa_modules.h b/trunk/drivers/scsi/bfa/bfa_modules.h index 1c6efd40a673..ab79ff6fdeea 100644 --- a/trunk/drivers/scsi/bfa/bfa_modules.h +++ b/trunk/drivers/scsi/bfa/bfa_modules.h @@ -29,21 +29,14 @@ #include "bfa_port.h" struct bfa_modules_s { - struct bfa_fcdiag_s fcdiag; /* fcdiag module */ struct bfa_fcport_s fcport; /* fc port module */ struct bfa_fcxp_mod_s fcxp_mod; /* fcxp module */ struct bfa_lps_mod_s lps_mod; /* fcxp module */ struct bfa_uf_mod_s uf_mod; /* unsolicited frame module */ struct bfa_rport_mod_s rport_mod; /* remote port module */ - struct bfa_fcp_mod_s fcp_mod; /* FCP initiator module */ + struct bfa_fcpim_mod_s fcpim_mod; /* FCP initiator module */ struct bfa_sgpg_mod_s sgpg_mod; /* SG page module */ struct bfa_port_s port; /* Physical port module */ - struct bfa_ablk_s ablk; /* ASIC block config module */ - struct bfa_cee_s cee; /* CEE Module */ - struct bfa_sfp_s sfp; /* SFP module */ - struct bfa_flash_s flash; /* flash module */ - struct bfa_diag_s diag_mod; /* diagnostics module */ - struct bfa_phy_s phy; /* phy module */ }; /* @@ -58,16 +51,17 @@ enum { BFA_TRC_HAL_IOCFC_CB = 5, }; + /* * Macro to define a new BFA module */ #define BFA_MODULE(__mod) \ static void bfa_ ## __mod ## _meminfo( \ - struct bfa_iocfc_cfg_s *cfg, \ - struct bfa_meminfo_s *meminfo, \ - struct bfa_s *bfa); \ + struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, \ + u32 *dm_len); \ static void bfa_ ## __mod ## _attach(struct bfa_s *bfa, \ void *bfad, struct bfa_iocfc_cfg_s *cfg, \ + struct bfa_meminfo_s *meminfo, \ struct bfa_pcidev_s *pcidev); \ static void bfa_ ## __mod ## _detach(struct bfa_s *bfa); \ static void bfa_ ## __mod ## _start(struct bfa_s *bfa); \ @@ -93,11 +87,11 @@ enum { * can leave entry points as NULL) */ struct bfa_module_s { - void (*meminfo) (struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa); + void (*meminfo) (struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len); void (*attach) (struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev); void (*detach) (struct bfa_s *bfa); void (*start) (struct bfa_s *bfa); @@ -115,20 +109,19 @@ struct bfa_s { struct bfa_timer_mod_s timer_mod; /* timer module */ struct bfa_modules_s modules; /* BFA modules */ struct list_head comp_q; /* pending completions */ - bfa_boolean_t queue_process; /* queue processing enabled */ + bfa_boolean_t rme_process; /* RME processing enabled */ struct list_head reqq_waitq[BFI_IOC_MAX_CQS]; bfa_boolean_t fcs; /* FCS is attached to BFA */ struct bfa_msix_s msix; }; extern bfa_boolean_t bfa_auto_recover; -extern struct bfa_module_s hal_mod_fcdiag; extern struct bfa_module_s hal_mod_sgpg; extern struct bfa_module_s hal_mod_fcport; extern struct bfa_module_s hal_mod_fcxp; extern struct bfa_module_s hal_mod_lps; extern struct bfa_module_s hal_mod_uf; extern struct bfa_module_s hal_mod_rport; -extern struct bfa_module_s hal_mod_fcp; +extern struct bfa_module_s hal_mod_fcpim; #endif /* __BFA_MODULES_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfa_port.c b/trunk/drivers/scsi/bfa/bfa_port.c index 95e4ad8759ac..3f8e9d6066ec 100644 --- a/trunk/drivers/scsi/bfa/bfa_port.c +++ b/trunk/drivers/scsi/bfa/bfa_port.c @@ -24,6 +24,8 @@ BFA_TRC_FILE(CNA, PORT); +#define bfa_ioc_portid(__ioc) ((__ioc)->port_id) + static void bfa_port_stats_swap(struct bfa_port_s *port, union bfa_port_stats_u *stats) { @@ -234,12 +236,6 @@ bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, { struct bfi_port_generic_req_s *m; - /* If port is PBC disabled, return error */ - if (port->pbc_disabled) { - bfa_trc(port, BFA_STATUS_PBC); - return BFA_STATUS_PBC; - } - if (bfa_ioc_is_disabled(port->ioc)) { bfa_trc(port, BFA_STATUS_IOC_DISABLED); return BFA_STATUS_IOC_DISABLED; @@ -284,12 +280,6 @@ bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, { struct bfi_port_generic_req_s *m; - /* If port is PBC disabled, return error */ - if (port->pbc_disabled) { - bfa_trc(port, BFA_STATUS_PBC); - return BFA_STATUS_PBC; - } - if (bfa_ioc_is_disabled(port->ioc)) { bfa_trc(port, BFA_STATUS_IOC_DISABLED); return BFA_STATUS_IOC_DISABLED; @@ -397,43 +387,32 @@ bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn, } /* - * bfa_port_notify() + * bfa_port_hbfail() * - * Port module IOC event handler * * @param[in] Pointer to the Port module data structure. - * @param[in] IOC event structure * * @return void */ void -bfa_port_notify(void *arg, enum bfa_ioc_event_e event) +bfa_port_hbfail(void *arg) { struct bfa_port_s *port = (struct bfa_port_s *) arg; - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - /* Fail any pending get_stats/clear_stats requests */ - if (port->stats_busy) { - if (port->stats_cbfn) - port->stats_cbfn(port->stats_cbarg, - BFA_STATUS_FAILED); - port->stats_cbfn = NULL; - port->stats_busy = BFA_FALSE; - } - - /* Clear any enable/disable is pending */ - if (port->endis_pending) { - if (port->endis_cbfn) - port->endis_cbfn(port->endis_cbarg, - BFA_STATUS_FAILED); - port->endis_cbfn = NULL; - port->endis_pending = BFA_FALSE; - } - break; - default: - break; + /* Fail any pending get_stats/clear_stats requests */ + if (port->stats_busy) { + if (port->stats_cbfn) + port->stats_cbfn(port->stats_cbarg, BFA_STATUS_FAILED); + port->stats_cbfn = NULL; + port->stats_busy = BFA_FALSE; + } + + /* Clear any enable/disable is pending */ + if (port->endis_pending) { + if (port->endis_cbfn) + port->endis_cbfn(port->endis_cbarg, BFA_STATUS_FAILED); + port->endis_cbfn = NULL; + port->endis_pending = BFA_FALSE; } } @@ -466,12 +445,10 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, port->endis_pending = BFA_FALSE; port->stats_cbfn = NULL; port->endis_cbfn = NULL; - port->pbc_disabled = BFA_FALSE; bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port); - bfa_q_qe_init(&port->ioc_notify); - bfa_ioc_notify_init(&port->ioc_notify, bfa_port_notify, port); - list_add_tail(&port->ioc_notify.qe, &port->ioc->notify_q); + bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port); + list_add_tail(&port->hbfail.qe, &port->ioc->hb_notify_q); /* * initialize time stamp for stats reset @@ -481,368 +458,3 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, bfa_trc(port, 0); } - -/* - * CEE module specific definitions - */ - -/* - * bfa_cee_get_attr_isr() - * - * @brief CEE ISR for get-attributes responses from f/w - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_get_attr_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - struct bfa_cee_lldp_cfg_s *lldp_cfg = &cee->attr->lldp_remote; - - cee->get_attr_status = status; - bfa_trc(cee, 0); - if (status == BFA_STATUS_OK) { - bfa_trc(cee, 0); - memcpy(cee->attr, cee->attr_dma.kva, - sizeof(struct bfa_cee_attr_s)); - lldp_cfg->time_to_live = be16_to_cpu(lldp_cfg->time_to_live); - lldp_cfg->enabled_system_cap = - be16_to_cpu(lldp_cfg->enabled_system_cap); - } - cee->get_attr_pending = BFA_FALSE; - if (cee->cbfn.get_attr_cbfn) { - bfa_trc(cee, 0); - cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status); - } -} - -/* - * bfa_cee_get_stats_isr() - * - * @brief CEE ISR for get-stats responses from f/w - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_get_stats_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - u32 *buffer; - int i; - - cee->get_stats_status = status; - bfa_trc(cee, 0); - if (status == BFA_STATUS_OK) { - bfa_trc(cee, 0); - memcpy(cee->stats, cee->stats_dma.kva, - sizeof(struct bfa_cee_stats_s)); - /* swap the cee stats */ - buffer = (u32 *)cee->stats; - for (i = 0; i < (sizeof(struct bfa_cee_stats_s) / - sizeof(u32)); i++) - buffer[i] = cpu_to_be32(buffer[i]); - } - cee->get_stats_pending = BFA_FALSE; - bfa_trc(cee, 0); - if (cee->cbfn.get_stats_cbfn) { - bfa_trc(cee, 0); - cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status); - } -} - -/* - * bfa_cee_reset_stats_isr() - * - * @brief CEE ISR for reset-stats responses from f/w - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_reset_stats_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - cee->reset_stats_status = status; - cee->reset_stats_pending = BFA_FALSE; - if (cee->cbfn.reset_stats_cbfn) - cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status); -} - -/* - * bfa_cee_meminfo() - * - * @brief Returns the size of the DMA memory needed by CEE module - * - * @param[in] void - * - * @return Size of DMA region - */ -u32 -bfa_cee_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ) + - BFA_ROUNDUP(sizeof(struct bfa_cee_stats_s), BFA_DMA_ALIGN_SZ); -} - -/* - * bfa_cee_mem_claim() - * - * @brief Initialized CEE DMA Memory - * - * @param[in] cee CEE module pointer - * dma_kva Kernel Virtual Address of CEE DMA Memory - * dma_pa Physical Address of CEE DMA Memory - * - * @return void - */ -void -bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa) -{ - cee->attr_dma.kva = dma_kva; - cee->attr_dma.pa = dma_pa; - cee->stats_dma.kva = dma_kva + BFA_ROUNDUP( - sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ); - cee->stats_dma.pa = dma_pa + BFA_ROUNDUP( - sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ); - cee->attr = (struct bfa_cee_attr_s *) dma_kva; - cee->stats = (struct bfa_cee_stats_s *) (dma_kva + BFA_ROUNDUP( - sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ)); -} - -/* - * bfa_cee_get_attr() - * - * @brief - * Send the request to the f/w to fetch CEE attributes. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_get_attr(struct bfa_cee_s *cee, struct bfa_cee_attr_s *attr, - bfa_cee_get_attr_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_get_req_s *cmd; - - WARN_ON((cee == NULL) || (cee->ioc == NULL)); - bfa_trc(cee, 0); - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->get_attr_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->get_attr_pending = BFA_TRUE; - cmd = (struct bfi_cee_get_req_s *) cee->get_cfg_mb.msg; - cee->attr = attr; - cee->cbfn.get_attr_cbfn = cbfn; - cee->cbfn.get_attr_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ, - bfa_ioc_portid(cee->ioc)); - bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa); - bfa_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_cee_get_stats() - * - * @brief - * Send the request to the f/w to fetch CEE statistics. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_get_stats(struct bfa_cee_s *cee, struct bfa_cee_stats_s *stats, - bfa_cee_get_stats_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_get_req_s *cmd; - - WARN_ON((cee == NULL) || (cee->ioc == NULL)); - - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->get_stats_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->get_stats_pending = BFA_TRUE; - cmd = (struct bfi_cee_get_req_s *) cee->get_stats_mb.msg; - cee->stats = stats; - cee->cbfn.get_stats_cbfn = cbfn; - cee->cbfn.get_stats_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ, - bfa_ioc_portid(cee->ioc)); - bfa_dma_be_addr_set(cmd->dma_addr, cee->stats_dma.pa); - bfa_ioc_mbox_queue(cee->ioc, &cee->get_stats_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_cee_reset_stats() - * - * @brief Clears CEE Stats in the f/w. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_reset_stats(struct bfa_cee_s *cee, - bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_reset_stats_s *cmd; - - WARN_ON((cee == NULL) || (cee->ioc == NULL)); - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->reset_stats_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->reset_stats_pending = BFA_TRUE; - cmd = (struct bfi_cee_reset_stats_s *) cee->reset_stats_mb.msg; - cee->cbfn.reset_stats_cbfn = cbfn; - cee->cbfn.reset_stats_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS, - bfa_ioc_portid(cee->ioc)); - bfa_ioc_mbox_queue(cee->ioc, &cee->reset_stats_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_cee_isrs() - * - * @brief Handles Mail-box interrupts for CEE module. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return void - */ - -void -bfa_cee_isr(void *cbarg, struct bfi_mbmsg_s *m) -{ - union bfi_cee_i2h_msg_u *msg; - struct bfi_cee_get_rsp_s *get_rsp; - struct bfa_cee_s *cee = (struct bfa_cee_s *) cbarg; - msg = (union bfi_cee_i2h_msg_u *) m; - get_rsp = (struct bfi_cee_get_rsp_s *) m; - bfa_trc(cee, msg->mh.msg_id); - switch (msg->mh.msg_id) { - case BFI_CEE_I2H_GET_CFG_RSP: - bfa_trc(cee, get_rsp->cmd_status); - bfa_cee_get_attr_isr(cee, get_rsp->cmd_status); - break; - case BFI_CEE_I2H_GET_STATS_RSP: - bfa_cee_get_stats_isr(cee, get_rsp->cmd_status); - break; - case BFI_CEE_I2H_RESET_STATS_RSP: - bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status); - break; - default: - WARN_ON(1); - } -} - -/* - * bfa_cee_notify() - * - * @brief CEE module IOC event handler. - * - * @param[in] Pointer to the CEE module data structure. - * @param[in] IOC event type - * - * @return void - */ - -void -bfa_cee_notify(void *arg, enum bfa_ioc_event_e event) -{ - struct bfa_cee_s *cee = (struct bfa_cee_s *) arg; - - bfa_trc(cee, event); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (cee->get_attr_pending == BFA_TRUE) { - cee->get_attr_status = BFA_STATUS_FAILED; - cee->get_attr_pending = BFA_FALSE; - if (cee->cbfn.get_attr_cbfn) { - cee->cbfn.get_attr_cbfn( - cee->cbfn.get_attr_cbarg, - BFA_STATUS_FAILED); - } - } - if (cee->get_stats_pending == BFA_TRUE) { - cee->get_stats_status = BFA_STATUS_FAILED; - cee->get_stats_pending = BFA_FALSE; - if (cee->cbfn.get_stats_cbfn) { - cee->cbfn.get_stats_cbfn( - cee->cbfn.get_stats_cbarg, - BFA_STATUS_FAILED); - } - } - if (cee->reset_stats_pending == BFA_TRUE) { - cee->reset_stats_status = BFA_STATUS_FAILED; - cee->reset_stats_pending = BFA_FALSE; - if (cee->cbfn.reset_stats_cbfn) { - cee->cbfn.reset_stats_cbfn( - cee->cbfn.reset_stats_cbarg, - BFA_STATUS_FAILED); - } - } - break; - - default: - break; - } -} - -/* - * bfa_cee_attach() - * - * @brief CEE module-attach API - * - * @param[in] cee - Pointer to the CEE module data structure - * ioc - Pointer to the ioc module data structure - * dev - Pointer to the device driver module data structure - * The device driver specific mbox ISR functions have - * this pointer as one of the parameters. - * - * @return void - */ -void -bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, - void *dev) -{ - WARN_ON(cee == NULL); - cee->dev = dev; - cee->ioc = ioc; - - bfa_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee); - bfa_q_qe_init(&cee->ioc_notify); - bfa_ioc_notify_init(&cee->ioc_notify, bfa_cee_notify, cee); - list_add_tail(&cee->ioc_notify.qe, &cee->ioc->notify_q); -} diff --git a/trunk/drivers/scsi/bfa/bfa_port.h b/trunk/drivers/scsi/bfa/bfa_port.h index 947f897328d6..c4ee9db6b470 100644 --- a/trunk/drivers/scsi/bfa/bfa_port.h +++ b/trunk/drivers/scsi/bfa/bfa_port.h @@ -43,16 +43,12 @@ struct bfa_port_s { bfa_port_endis_cbfn_t endis_cbfn; void *endis_cbarg; bfa_status_t endis_status; - struct bfa_ioc_notify_s ioc_notify; - bfa_boolean_t pbc_disabled; - struct bfa_mem_dma_s port_dma; + struct bfa_ioc_hbfail_notify_s hbfail; }; -#define BFA_MEM_PORT_DMA(__bfa) (&((__bfa)->modules.port.port_dma)) - void bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev, struct bfa_trc_mod_s *trcmod); -void bfa_port_notify(void *arg, enum bfa_ioc_event_e event); +void bfa_port_hbfail(void *arg); bfa_status_t bfa_port_get_stats(struct bfa_port_s *port, union bfa_port_stats_u *stats, @@ -66,58 +62,4 @@ bfa_status_t bfa_port_disable(struct bfa_port_s *port, u32 bfa_port_meminfo(void); void bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa); - -/* - * CEE declaration - */ -typedef void (*bfa_cee_get_attr_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_cee_get_stats_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_cee_reset_stats_cbfn_t) (void *dev, bfa_status_t status); - -struct bfa_cee_cbfn_s { - bfa_cee_get_attr_cbfn_t get_attr_cbfn; - void *get_attr_cbarg; - bfa_cee_get_stats_cbfn_t get_stats_cbfn; - void *get_stats_cbarg; - bfa_cee_reset_stats_cbfn_t reset_stats_cbfn; - void *reset_stats_cbarg; -}; - -struct bfa_cee_s { - void *dev; - bfa_boolean_t get_attr_pending; - bfa_boolean_t get_stats_pending; - bfa_boolean_t reset_stats_pending; - bfa_status_t get_attr_status; - bfa_status_t get_stats_status; - bfa_status_t reset_stats_status; - struct bfa_cee_cbfn_s cbfn; - struct bfa_ioc_notify_s ioc_notify; - struct bfa_trc_mod_s *trcmod; - struct bfa_cee_attr_s *attr; - struct bfa_cee_stats_s *stats; - struct bfa_dma_s attr_dma; - struct bfa_dma_s stats_dma; - struct bfa_ioc_s *ioc; - struct bfa_mbox_cmd_s get_cfg_mb; - struct bfa_mbox_cmd_s get_stats_mb; - struct bfa_mbox_cmd_s reset_stats_mb; - struct bfa_mem_dma_s cee_dma; -}; - -#define BFA_MEM_CEE_DMA(__bfa) (&((__bfa)->modules.cee.cee_dma)) - -u32 bfa_cee_meminfo(void); -void bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa); -void bfa_cee_attach(struct bfa_cee_s *cee, - struct bfa_ioc_s *ioc, void *dev); -bfa_status_t bfa_cee_get_attr(struct bfa_cee_s *cee, - struct bfa_cee_attr_s *attr, - bfa_cee_get_attr_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_cee_get_stats(struct bfa_cee_s *cee, - struct bfa_cee_stats_s *stats, - bfa_cee_get_stats_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_cee_reset_stats(struct bfa_cee_s *cee, - bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg); - #endif /* __BFA_PORT_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfa_svc.c b/trunk/drivers/scsi/bfa/bfa_svc.c index 21caaefce99f..16d9a5f61c18 100644 --- a/trunk/drivers/scsi/bfa/bfa_svc.c +++ b/trunk/drivers/scsi/bfa/bfa_svc.c @@ -21,7 +21,6 @@ #include "bfa_modules.h" BFA_TRC_FILE(HAL, FCXP); -BFA_MODULE(fcdiag); BFA_MODULE(fcxp); BFA_MODULE(sgpg); BFA_MODULE(lps); @@ -114,10 +113,11 @@ static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, /* * forward declarations for LPS functions */ -static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *minfo, struct bfa_s *bfa); +static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len); static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev); static void bfa_lps_detach(struct bfa_s *bfa); static void bfa_lps_start(struct bfa_s *bfa); @@ -125,7 +125,6 @@ static void bfa_lps_stop(struct bfa_s *bfa); static void bfa_lps_iocdisable(struct bfa_s *bfa); static void bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp); -static void bfa_lps_no_res(struct bfa_lps_s *first_lps, u8 count); static void bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp); static void bfa_lps_reqq_resume(void *lps_arg); @@ -431,17 +430,51 @@ bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid, */ static void -claim_fcxps_mem(struct bfa_fcxp_mod_s *mod) +claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) +{ + u8 *dm_kva = NULL; + u64 dm_pa; + u32 buf_pool_sz; + + dm_kva = bfa_meminfo_dma_virt(mi); + dm_pa = bfa_meminfo_dma_phys(mi); + + buf_pool_sz = mod->req_pld_sz * mod->num_fcxps; + + /* + * Initialize the fcxp req payload list + */ + mod->req_pld_list_kva = dm_kva; + mod->req_pld_list_pa = dm_pa; + dm_kva += buf_pool_sz; + dm_pa += buf_pool_sz; + memset(mod->req_pld_list_kva, 0, buf_pool_sz); + + /* + * Initialize the fcxp rsp payload list + */ + buf_pool_sz = mod->rsp_pld_sz * mod->num_fcxps; + mod->rsp_pld_list_kva = dm_kva; + mod->rsp_pld_list_pa = dm_pa; + dm_kva += buf_pool_sz; + dm_pa += buf_pool_sz; + memset(mod->rsp_pld_list_kva, 0, buf_pool_sz); + + bfa_meminfo_dma_virt(mi) = dm_kva; + bfa_meminfo_dma_phys(mi) = dm_pa; +} + +static void +claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) { u16 i; struct bfa_fcxp_s *fcxp; - fcxp = (struct bfa_fcxp_s *) bfa_mem_kva_curp(mod); + fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi); memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps); INIT_LIST_HEAD(&mod->fcxp_free_q); INIT_LIST_HEAD(&mod->fcxp_active_q); - INIT_LIST_HEAD(&mod->fcxp_unused_q); mod->fcxp_list = fcxp; @@ -456,53 +489,40 @@ claim_fcxps_mem(struct bfa_fcxp_mod_s *mod) fcxp = fcxp + 1; } - bfa_mem_kva_curp(mod) = (void *)fcxp; + bfa_meminfo_kva(mi) = (void *)fcxp; } static void -bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len) { - struct bfa_fcxp_mod_s *fcxp_mod = BFA_FCXP_MOD(bfa); - struct bfa_mem_kva_s *fcxp_kva = BFA_MEM_FCXP_KVA(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_fcxp; - u16 num_fcxps = cfg->fwcfg.num_fcxp_reqs; - u32 per_fcxp_sz; + u16 num_fcxp_reqs = cfg->fwcfg.num_fcxp_reqs; - if (num_fcxps == 0) + if (num_fcxp_reqs == 0) return; + /* + * Account for req/rsp payload + */ + *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; if (cfg->drvcfg.min_cfg) - per_fcxp_sz = 2 * BFA_FCXP_MAX_IBUF_SZ; + *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; else - per_fcxp_sz = BFA_FCXP_MAX_IBUF_SZ + BFA_FCXP_MAX_LBUF_SZ; - - /* dma memory */ - nsegs = BFI_MEM_DMA_NSEGS(num_fcxps, per_fcxp_sz); - per_seg_fcxp = BFI_MEM_NREQS_SEG(per_fcxp_sz); - - bfa_mem_dma_seg_iter(fcxp_mod, seg_ptr, nsegs, idx) { - if (num_fcxps >= per_seg_fcxp) { - num_fcxps -= per_seg_fcxp; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_fcxp * per_fcxp_sz); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_fcxps * per_fcxp_sz); - } + *dm_len += BFA_FCXP_MAX_LBUF_SZ * num_fcxp_reqs; - /* kva memory */ - bfa_mem_kva_setup(minfo, fcxp_kva, - cfg->fwcfg.num_fcxp_reqs * sizeof(struct bfa_fcxp_s)); + /* + * Account for fcxp structs + */ + *ndm_len += sizeof(struct bfa_fcxp_s) * num_fcxp_reqs; } static void bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + memset(mod, 0, sizeof(struct bfa_fcxp_mod_s)); mod->bfa = bfa; mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs; @@ -515,7 +535,8 @@ bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, INIT_LIST_HEAD(&mod->wait_q); - claim_fcxps_mem(mod); + claim_fcxp_req_rsp_mem(mod, meminfo); + claim_fcxps_mem(mod, meminfo); } static void @@ -540,9 +561,6 @@ bfa_fcxp_iocdisable(struct bfa_s *bfa) struct bfa_fcxp_s *fcxp; struct list_head *qe, *qen; - /* Enqueue unused fcxp resources to free_q */ - list_splice_tail_init(&mod->fcxp_unused_q, &mod->fcxp_free_q); - list_for_each_safe(qe, qen, &mod->fcxp_active_q) { fcxp = (struct bfa_fcxp_s *) qe; if (fcxp->caller == NULL) { @@ -731,6 +749,23 @@ hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp) } } +static void +hal_fcxp_set_local_sges(struct bfi_sge_s *sge, u32 reqlen, u64 req_pa) +{ + union bfi_addr_u sga_zero = { {0} }; + + sge->sg_len = reqlen; + sge->flags = BFI_SGE_DATA_LAST; + bfa_dma_addr_set(sge[0].sga, req_pa); + bfa_sge_to_be(sge); + sge++; + + sge->sga = sga_zero; + sge->sg_len = reqlen; + sge->flags = BFI_SGE_PGDLEN; + bfa_sge_to_be(sge); +} + static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp, struct fchs_s *fchs) @@ -811,7 +846,7 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) struct bfa_rport_s *rport = reqi->bfa_rport; bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ, - bfa_fn_lpu(bfa)); + bfa_lpuid(bfa)); send_req->fcxp_tag = cpu_to_be16(fcxp->fcxp_tag); if (rport) { @@ -825,7 +860,7 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) } send_req->vf_id = cpu_to_be16(reqi->vf_id); - send_req->lp_fwtag = bfa_lps_get_fwtag(bfa, reqi->lp_tag); + send_req->lp_tag = reqi->lp_tag; send_req->class = reqi->class; send_req->rsp_timeout = rspi->rsp_timeout; send_req->cts = reqi->cts; @@ -838,16 +873,18 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) * setup req sgles */ if (fcxp->use_ireqbuf == 1) { - bfa_alen_set(&send_req->req_alen, reqi->req_tot_len, + hal_fcxp_set_local_sges(send_req->req_sge, reqi->req_tot_len, BFA_FCXP_REQ_PLD_PA(fcxp)); } else { if (fcxp->nreq_sgles > 0) { WARN_ON(fcxp->nreq_sgles != 1); - bfa_alen_set(&send_req->req_alen, reqi->req_tot_len, - fcxp->req_sga_cbfn(fcxp->caller, 0)); + hal_fcxp_set_local_sges(send_req->req_sge, + reqi->req_tot_len, + fcxp->req_sga_cbfn(fcxp->caller, + 0)); } else { WARN_ON(reqi->req_tot_len != 0); - bfa_alen_set(&send_req->rsp_alen, 0, 0); + hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); } } @@ -857,23 +894,25 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) if (fcxp->use_irspbuf == 1) { WARN_ON(rspi->rsp_maxlen > BFA_FCXP_MAX_LBUF_SZ); - bfa_alen_set(&send_req->rsp_alen, rspi->rsp_maxlen, + hal_fcxp_set_local_sges(send_req->rsp_sge, rspi->rsp_maxlen, BFA_FCXP_RSP_PLD_PA(fcxp)); + } else { if (fcxp->nrsp_sgles > 0) { WARN_ON(fcxp->nrsp_sgles != 1); - bfa_alen_set(&send_req->rsp_alen, rspi->rsp_maxlen, - fcxp->rsp_sga_cbfn(fcxp->caller, 0)); - + hal_fcxp_set_local_sges(send_req->rsp_sge, + rspi->rsp_maxlen, + fcxp->rsp_sga_cbfn(fcxp->caller, + 0)); } else { WARN_ON(rspi->rsp_maxlen != 0); - bfa_alen_set(&send_req->rsp_alen, 0, 0); + hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); } } hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs); - bfa_reqq_produce(bfa, BFA_REQQ_FCXP, send_req->mh); + bfa_reqq_produce(bfa, BFA_REQQ_FCXP); bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP)); bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP)); @@ -939,8 +978,8 @@ bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp) void *reqbuf; WARN_ON(fcxp->use_ireqbuf != 1); - reqbuf = bfa_mem_get_dmabuf_kva(mod, fcxp->fcxp_tag, - mod->req_pld_sz + mod->rsp_pld_sz); + reqbuf = ((u8 *)mod->req_pld_list_kva) + + fcxp->fcxp_tag * mod->req_pld_sz; return reqbuf; } @@ -963,15 +1002,13 @@ void * bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp) { struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - void *fcxp_buf; + void *rspbuf; WARN_ON(fcxp->use_irspbuf != 1); - fcxp_buf = bfa_mem_get_dmabuf_kva(mod, fcxp->fcxp_tag, - mod->req_pld_sz + mod->rsp_pld_sz); - - /* fcxp_buf = req_buf + rsp_buf :- add req_buf_sz to get to rsp_buf */ - return ((u8 *) fcxp_buf) + mod->req_pld_sz; + rspbuf = ((u8 *)mod->rsp_pld_list_kva) + + fcxp->fcxp_tag * mod->rsp_pld_sz; + return rspbuf; } /* @@ -1144,18 +1181,6 @@ bfa_fcxp_get_maxrsp(struct bfa_s *bfa) return mod->rsp_pld_sz; } -void -bfa_fcxp_res_recfg(struct bfa_s *bfa, u16 num_fcxp_fw) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (mod->num_fcxps - num_fcxp_fw); i++) { - bfa_q_deq_tail(&mod->fcxp_free_q, &qe); - list_add_tail(qe, &mod->fcxp_unused_q); - } -} /* * BFA LPS state machine functions @@ -1167,7 +1192,7 @@ bfa_fcxp_res_recfg(struct bfa_s *bfa, u16 num_fcxp_fw) static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1219,7 +1244,7 @@ bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1253,7 +1278,6 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) break; case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: bfa_sm_set_state(lps, bfa_lps_sm_init); break; @@ -1273,7 +1297,7 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1282,7 +1306,6 @@ bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) break; case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: bfa_sm_set_state(lps, bfa_lps_sm_init); bfa_reqq_wcancel(&lps->wqe); break; @@ -1306,7 +1329,7 @@ bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1355,7 +1378,7 @@ bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1397,7 +1420,7 @@ bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1407,7 +1430,6 @@ bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) break; case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: bfa_sm_set_state(lps, bfa_lps_sm_init); break; @@ -1422,7 +1444,7 @@ bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, event); switch (event) { @@ -1432,7 +1454,6 @@ bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) break; case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: bfa_sm_set_state(lps, bfa_lps_sm_init); bfa_reqq_wcancel(&lps->wqe); break; @@ -1452,17 +1473,13 @@ bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) * return memory requirement */ static void -bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len) { - struct bfa_mem_kva_s *lps_kva = BFA_MEM_LPS_KVA(bfa); - if (cfg->drvcfg.min_cfg) - bfa_mem_kva_setup(minfo, lps_kva, - sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS); + *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS; else - bfa_mem_kva_setup(minfo, lps_kva, - sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS); + *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS; } /* @@ -1470,28 +1487,28 @@ bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, */ static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); struct bfa_lps_s *lps; int i; + memset(mod, 0, sizeof(struct bfa_lps_mod_s)); mod->num_lps = BFA_LPS_MAX_LPORTS; if (cfg->drvcfg.min_cfg) mod->num_lps = BFA_LPS_MIN_LPORTS; else mod->num_lps = BFA_LPS_MAX_LPORTS; - mod->lps_arr = lps = (struct bfa_lps_s *) bfa_mem_kva_curp(mod); + mod->lps_arr = lps = (struct bfa_lps_s *) bfa_meminfo_kva(meminfo); - bfa_mem_kva_curp(mod) += mod->num_lps * sizeof(struct bfa_lps_s); + bfa_meminfo_kva(meminfo) += mod->num_lps * sizeof(struct bfa_lps_s); INIT_LIST_HEAD(&mod->lps_free_q); INIT_LIST_HEAD(&mod->lps_active_q); - INIT_LIST_HEAD(&mod->lps_login_q); for (i = 0; i < mod->num_lps; i++, lps++) { lps->bfa = bfa; - lps->bfa_tag = (u8) i; + lps->lp_tag = (u8) i; lps->reqq = BFA_REQQ_LPS; bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps); list_add_tail(&lps->qe, &mod->lps_free_q); @@ -1527,11 +1544,6 @@ bfa_lps_iocdisable(struct bfa_s *bfa) lps = (struct bfa_lps_s *) qe; bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); } - list_for_each_safe(qe, qen, &mod->lps_login_q) { - lps = (struct bfa_lps_s *) qe; - bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); - } - list_splice_tail_init(&mod->lps_login_q, &mod->lps_active_q); } /* @@ -1543,13 +1555,12 @@ bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); struct bfa_lps_s *lps; - WARN_ON(rsp->bfa_tag >= mod->num_lps); - lps = BFA_LPS_FROM_TAG(mod, rsp->bfa_tag); + WARN_ON(rsp->lp_tag >= mod->num_lps); + lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); lps->status = rsp->status; switch (rsp->status) { case BFA_STATUS_OK: - lps->fw_tag = rsp->fw_tag; lps->fport = rsp->f_port; if (lps->fport) lps->lp_pid = rsp->lp_pid; @@ -1561,7 +1572,6 @@ bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) lps->lp_mac = rsp->lp_mac; lps->brcd_switch = rsp->brcd_switch; lps->fcf_mac = rsp->fcf_mac; - lps->pr_bbscn = rsp->bb_scn; break; @@ -1576,46 +1586,14 @@ bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) break; - case BFA_STATUS_VPORT_MAX: - if (!rsp->ext_status) - bfa_lps_no_res(lps, rsp->ext_status); - break; - default: /* Nothing to do with other status */ break; } - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_active_q); bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); } -static void -bfa_lps_no_res(struct bfa_lps_s *first_lps, u8 count) -{ - struct bfa_s *bfa = first_lps->bfa; - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct list_head *qe, *qe_next; - struct bfa_lps_s *lps; - - bfa_trc(bfa, count); - - qe = bfa_q_next(first_lps); - - while (count && qe) { - qe_next = bfa_q_next(qe); - lps = (struct bfa_lps_s *)qe; - bfa_trc(bfa, lps->bfa_tag); - lps->status = first_lps->status; - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_active_q); - bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); - qe = qe_next; - count--; - } -} - /* * Firmware logout response */ @@ -1625,8 +1603,8 @@ bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp) struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); struct bfa_lps_s *lps; - WARN_ON(rsp->bfa_tag >= mod->num_lps); - lps = BFA_LPS_FROM_TAG(mod, rsp->bfa_tag); + WARN_ON(rsp->lp_tag >= mod->num_lps); + lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); } @@ -1640,7 +1618,7 @@ bfa_lps_rx_cvl_event(struct bfa_s *bfa, struct bfi_lps_cvl_event_s *cvl) struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); struct bfa_lps_s *lps; - lps = BFA_LPS_FROM_TAG(mod, cvl->bfa_tag); + lps = BFA_LPS_FROM_TAG(mod, cvl->lp_tag); bfa_sm_send_event(lps, BFA_LPS_SM_RX_CVL); } @@ -1675,27 +1653,23 @@ bfa_lps_free(struct bfa_lps_s *lps) static void bfa_lps_send_login(struct bfa_lps_s *lps) { - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa); struct bfi_lps_login_req_s *m; m = bfa_reqq_next(lps->bfa, lps->reqq); WARN_ON(!m); bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ, - bfa_fn_lpu(lps->bfa)); + bfa_lpuid(lps->bfa)); - m->bfa_tag = lps->bfa_tag; + m->lp_tag = lps->lp_tag; m->alpa = lps->alpa; m->pdu_size = cpu_to_be16(lps->pdusz); m->pwwn = lps->pwwn; m->nwwn = lps->nwwn; m->fdisc = lps->fdisc; m->auth_en = lps->auth_en; - m->bb_scn = lps->bb_scn; - bfa_reqq_produce(lps->bfa, lps->reqq, m->mh); - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_login_q); + bfa_reqq_produce(lps->bfa, lps->reqq); } /* @@ -1710,11 +1684,11 @@ bfa_lps_send_logout(struct bfa_lps_s *lps) WARN_ON(!m); bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ, - bfa_fn_lpu(lps->bfa)); + bfa_lpuid(lps->bfa)); - m->fw_tag = lps->fw_tag; + m->lp_tag = lps->lp_tag; m->port_name = lps->pwwn; - bfa_reqq_produce(lps->bfa, lps->reqq, m->mh); + bfa_reqq_produce(lps->bfa, lps->reqq); } /* @@ -1729,11 +1703,11 @@ bfa_lps_send_set_n2n_pid(struct bfa_lps_s *lps) WARN_ON(!m); bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_N2N_PID_REQ, - bfa_fn_lpu(lps->bfa)); + bfa_lpuid(lps->bfa)); - m->fw_tag = lps->fw_tag; + m->lp_tag = lps->lp_tag; m->lp_pid = lps->lp_pid; - bfa_reqq_produce(lps->bfa, lps->reqq, m->mh); + bfa_reqq_produce(lps->bfa, lps->reqq); } /* @@ -1885,7 +1859,7 @@ bfa_lps_delete(struct bfa_lps_s *lps) */ void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, - wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en, uint8_t bb_scn) + wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en) { lps->uarg = uarg; lps->alpa = alpa; @@ -1894,7 +1868,6 @@ bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, lps->nwwn = nwwn; lps->fdisc = BFA_FALSE; lps->auth_en = auth_en; - lps->bb_scn = bb_scn; bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); } @@ -1925,13 +1898,6 @@ bfa_lps_fdisclogo(struct bfa_lps_s *lps) bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); } -u8 -bfa_lps_get_fwtag(struct bfa_s *bfa, u8 lp_tag) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - - return BFA_LPS_FROM_TAG(mod, lp_tag)->fw_tag; -} /* * Return lport services tag given the pid @@ -1945,7 +1911,7 @@ bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid) for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) { if (lps->lp_pid == pid) - return lps->bfa_tag; + return lps->lp_tag; } /* Return base port tag anyway */ @@ -1970,7 +1936,7 @@ bfa_lps_get_base_pid(struct bfa_s *bfa) void bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, uint32_t n2n_pid) { - bfa_trc(lps->bfa, lps->bfa_tag); + bfa_trc(lps->bfa, lps->lp_tag); bfa_trc(lps->bfa, n2n_pid); lps->lp_pid = n2n_pid; @@ -1989,15 +1955,15 @@ bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m) msg.msg = m; switch (m->mhdr.msg_id) { - case BFI_LPS_I2H_LOGIN_RSP: + case BFI_LPS_H2I_LOGIN_RSP: bfa_lps_login_rsp(bfa, msg.login_rsp); break; - case BFI_LPS_I2H_LOGOUT_RSP: + case BFI_LPS_H2I_LOGOUT_RSP: bfa_lps_logout_rsp(bfa, msg.logout_rsp); break; - case BFI_LPS_I2H_CVL_EVENT: + case BFI_LPS_H2I_CVL_EVENT: bfa_lps_rx_cvl_event(bfa, msg.cvl_event); break; @@ -2811,12 +2777,10 @@ bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln, enum bfa_port_linkstate event) BFA_CACHELINE_SZ)) static void -bfa_fcport_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_fcport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len) { - struct bfa_mem_dma_s *fcport_dma = BFA_MEM_FCPORT_DMA(bfa); - - bfa_mem_dma_setup(minfo, fcport_dma, FCPORT_STATS_DMA_SZ); + *dm_len += FCPORT_STATS_DMA_SZ; } static void @@ -2828,14 +2792,23 @@ bfa_fcport_qresume(void *cbarg) } static void -bfa_fcport_mem_claim(struct bfa_fcport_s *fcport) +bfa_fcport_mem_claim(struct bfa_fcport_s *fcport, struct bfa_meminfo_s *meminfo) { - struct bfa_mem_dma_s *fcport_dma = &fcport->fcport_dma; + u8 *dm_kva; + u64 dm_pa; - fcport->stats_kva = bfa_mem_dma_virt(fcport_dma); - fcport->stats_pa = bfa_mem_dma_phys(fcport_dma); - fcport->stats = (union bfa_fcport_stats_u *) - bfa_mem_dma_virt(fcport_dma); + dm_kva = bfa_meminfo_dma_virt(meminfo); + dm_pa = bfa_meminfo_dma_phys(meminfo); + + fcport->stats_kva = dm_kva; + fcport->stats_pa = dm_pa; + fcport->stats = (union bfa_fcport_stats_u *) dm_kva; + + dm_kva += FCPORT_STATS_DMA_SZ; + dm_pa += FCPORT_STATS_DMA_SZ; + + bfa_meminfo_dma_virt(meminfo) = dm_kva; + bfa_meminfo_dma_phys(meminfo) = dm_pa; } /* @@ -2843,17 +2816,18 @@ bfa_fcport_mem_claim(struct bfa_fcport_s *fcport) */ static void bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); struct bfa_port_cfg_s *port_cfg = &fcport->cfg; struct bfa_fcport_ln_s *ln = &fcport->ln; struct timeval tv; + memset(fcport, 0, sizeof(struct bfa_fcport_s)); fcport->bfa = bfa; ln->fcport = fcport; - bfa_fcport_mem_claim(fcport); + bfa_fcport_mem_claim(fcport, meminfo); bfa_sm_set_state(fcport, bfa_fcport_sm_uninit); bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn); @@ -2947,7 +2921,6 @@ bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport) { fcport->speed = BFA_PORT_SPEED_UNKNOWN; fcport->topology = BFA_PORT_TOPOLOGY_NONE; - fcport->bbsc_op_state = BFA_FALSE; } /* @@ -2975,7 +2948,7 @@ bfa_fcport_send_enable(struct bfa_fcport_s *fcport) } bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_ENABLE_REQ, - bfa_fn_lpu(fcport->bfa)); + bfa_lpuid(fcport->bfa)); m->nwwn = fcport->nwwn; m->pwwn = fcport->pwwn; m->port_cfg = fcport->cfg; @@ -2989,7 +2962,7 @@ bfa_fcport_send_enable(struct bfa_fcport_s *fcport) /* * queue I/O message to firmware */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, m->mh); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); return BFA_TRUE; } @@ -3018,13 +2991,13 @@ bfa_fcport_send_disable(struct bfa_fcport_s *fcport) } bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_DISABLE_REQ, - bfa_fn_lpu(fcport->bfa)); + bfa_lpuid(fcport->bfa)); m->msgtag = fcport->msgtag; /* * queue I/O message to firmware */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, m->mh); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); return BFA_TRUE; } @@ -3056,14 +3029,13 @@ bfa_fcport_send_txcredit(void *port_cbarg) } bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ, - bfa_fn_lpu(fcport->bfa)); + bfa_lpuid(fcport->bfa)); m->tx_bbcredit = cpu_to_be16((u16)fcport->cfg.tx_bbcredit); - m->bb_scn = fcport->cfg.bb_scn; /* * queue I/O message to firmware */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, m->mh); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); } static void @@ -3167,8 +3139,8 @@ bfa_fcport_send_stats_get(void *cbarg) memset(msg, 0, sizeof(struct bfi_fcport_req_s)); bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_GET_REQ, - bfa_fn_lpu(fcport->bfa)); - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, msg->mh); + bfa_lpuid(fcport->bfa)); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); } static void @@ -3229,8 +3201,8 @@ bfa_fcport_send_stats_clear(void *cbarg) memset(msg, 0, sizeof(struct bfi_fcport_req_s)); bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_CLEAR_REQ, - bfa_fn_lpu(fcport->bfa)); - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, msg->mh); + bfa_lpuid(fcport->bfa)); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); } /* @@ -3357,9 +3329,6 @@ bfa_fcport_init(struct bfa_s *bfa) fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc); fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc); - if (bfa_fcport_is_pbcdisabled(bfa)) - bfa->modules.port.pbc_disabled = BFA_TRUE; - WARN_ON(!fcport->cfg.maxfrsize); WARN_ON(!fcport->cfg.rx_bbcredit); WARN_ON(!fcport->speed_sup); @@ -3484,9 +3453,6 @@ bfa_fcport_enable(struct bfa_s *bfa) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - if (bfa_fcport_is_pbcdisabled(bfa)) - return BFA_STATUS_PBC; - if (bfa_ioc_is_disabled(&bfa->ioc)) return BFA_STATUS_IOC_DISABLED; @@ -3500,8 +3466,6 @@ bfa_fcport_enable(struct bfa_s *bfa) bfa_status_t bfa_fcport_disable(struct bfa_s *bfa) { - if (bfa_fcport_is_pbcdisabled(bfa)) - return BFA_STATUS_PBC; if (bfa_ioc_is_disabled(&bfa->ioc)) return BFA_STATUS_IOC_DISABLED; @@ -3510,21 +3474,6 @@ bfa_fcport_disable(struct bfa_s *bfa) return BFA_STATUS_OK; } -/* If PBC is disabled on port, return error */ -bfa_status_t -bfa_fcport_is_pbcdisabled(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; - - if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED) { - bfa_trc(bfa, fcport->pwwn); - return BFA_STATUS_PBC; - } - return BFA_STATUS_OK; -} - /* * Configure port speed. */ @@ -3542,28 +3491,6 @@ bfa_fcport_cfg_speed(struct bfa_s *bfa, enum bfa_port_speed speed) return BFA_STATUS_UNSUPP_SPEED; } - /* For Mezz card, port speed entered needs to be checked */ - if (bfa_mfg_is_mezz(fcport->bfa->ioc.attr->card_type)) { - if (bfa_ioc_get_type(&fcport->bfa->ioc) == BFA_IOC_TYPE_FC) { - /* For CT2, 1G is not supported */ - if ((speed == BFA_PORT_SPEED_1GBPS) && - (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id))) - return BFA_STATUS_UNSUPP_SPEED; - - /* Already checked for Auto Speed and Max Speed supp */ - if (!(speed == BFA_PORT_SPEED_1GBPS || - speed == BFA_PORT_SPEED_2GBPS || - speed == BFA_PORT_SPEED_4GBPS || - speed == BFA_PORT_SPEED_8GBPS || - speed == BFA_PORT_SPEED_16GBPS || - speed == BFA_PORT_SPEED_AUTO)) - return BFA_STATUS_UNSUPP_SPEED; - } else { - if (speed != BFA_PORT_SPEED_10GBPS) - return BFA_STATUS_UNSUPP_SPEED; - } - } - fcport->cfg.speed = speed; return BFA_STATUS_OK; @@ -3697,14 +3624,11 @@ bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa) } void -bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit, u8 bb_scn) +bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); fcport->cfg.tx_bbcredit = (u8)tx_bbcredit; - fcport->cfg.bb_scn = bb_scn; - if (bb_scn) - fcport->bbsc_op_state = BFA_TRUE; bfa_fcport_send_txcredit(fcport); } @@ -3751,23 +3675,16 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr) /* beacon attributes */ attr->beacon = fcport->beacon; attr->link_e2e_beacon = fcport->link_e2e_beacon; + attr->plog_enabled = (bfa_boolean_t)fcport->bfa->plog->plog_enabled; + attr->io_profile = bfa_fcpim_get_io_profile(fcport->bfa); attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa); attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa); attr->port_state = bfa_sm_to_state(hal_port_sm_table, fcport->sm); - attr->bbsc_op_status = fcport->bbsc_op_state; - - /* PBC Disabled State */ - if (bfa_fcport_is_pbcdisabled(bfa)) - attr->port_state = BFA_PORT_ST_PREBOOT_DISABLED; - else { - if (bfa_ioc_is_disabled(&fcport->bfa->ioc)) - attr->port_state = BFA_PORT_ST_IOCDIS; - else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc)) - attr->port_state = BFA_PORT_ST_FWMISMATCH; - else if (bfa_ioc_is_acq_addr(&fcport->bfa->ioc)) - attr->port_state = BFA_PORT_ST_ACQ_ADDR; - } + if (bfa_ioc_is_disabled(&fcport->bfa->ioc)) + attr->port_state = BFA_PORT_ST_IOCDIS; + else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc)) + attr->port_state = BFA_PORT_ST_FWMISMATCH; /* FCoE vlan */ attr->fcoe_vlan = fcport->fcoe_vlan; @@ -3848,18 +3765,6 @@ bfa_fcport_is_ratelim(struct bfa_s *bfa) } -/* - * Enable/Disable FAA feature in port config - */ -void -bfa_fcport_cfg_faa(struct bfa_s *bfa, u8 state) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, state); - fcport->cfg.faa_state = state; -} - /* * Get default minimum ratelim speed */ @@ -3873,22 +3778,6 @@ bfa_fcport_get_ratelim_speed(struct bfa_s *bfa) } -void -bfa_fcport_beacon(void *dev, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon) -{ - struct bfa_s *bfa = dev; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, beacon); - bfa_trc(bfa, link_e2e_beacon); - bfa_trc(bfa, fcport->beacon); - bfa_trc(bfa, fcport->link_e2e_beacon); - - fcport->beacon = beacon; - fcport->link_e2e_beacon = link_e2e_beacon; -} - bfa_boolean_t bfa_fcport_is_linkup(struct bfa_s *bfa) { @@ -3908,14 +3797,6 @@ bfa_fcport_is_qos_enabled(struct bfa_s *bfa) return fcport->cfg.qos_enabled; } -bfa_boolean_t -bfa_fcport_is_trunk_enabled(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->cfg.trunked; -} - /* * Rport State machine functions */ @@ -4405,22 +4286,18 @@ bfa_rport_qresume(void *cbarg) } static void -bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) { - struct bfa_mem_kva_s *rport_kva = BFA_MEM_RPORT_KVA(bfa); - if (cfg->fwcfg.num_rports < BFA_RPORT_MIN) cfg->fwcfg.num_rports = BFA_RPORT_MIN; - /* kva memory */ - bfa_mem_kva_setup(minfo, rport_kva, - cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s)); + *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s); } static void bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); struct bfa_rport_s *rp; @@ -4428,9 +4305,8 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, INIT_LIST_HEAD(&mod->rp_free_q); INIT_LIST_HEAD(&mod->rp_active_q); - INIT_LIST_HEAD(&mod->rp_unused_q); - rp = (struct bfa_rport_s *) bfa_mem_kva_curp(mod); + rp = (struct bfa_rport_s *) bfa_meminfo_kva(meminfo); mod->rps_list = rp; mod->num_rports = cfg->fwcfg.num_rports; @@ -4455,7 +4331,7 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, /* * consume memory */ - bfa_mem_kva_curp(mod) = (u8 *) rp; + bfa_meminfo_kva(meminfo) = (u8 *) rp; } static void @@ -4480,9 +4356,6 @@ bfa_rport_iocdisable(struct bfa_s *bfa) struct bfa_rport_s *rport; struct list_head *qe, *qen; - /* Enqueue unused rport resources to free_q */ - list_splice_tail_init(&mod->rp_unused_q, &mod->rp_free_q); - list_for_each_safe(qe, qen, &mod->rp_active_q) { rport = (struct bfa_rport_s *) qe; bfa_sm_send_event(rport, BFA_RPORT_SM_HWFAIL); @@ -4526,11 +4399,11 @@ bfa_rport_send_fwcreate(struct bfa_rport_s *rp) } bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ, - bfa_fn_lpu(rp->bfa)); + bfa_lpuid(rp->bfa)); m->bfa_handle = rp->rport_tag; m->max_frmsz = cpu_to_be16(rp->rport_info.max_frmsz); m->pid = rp->rport_info.pid; - m->lp_fwtag = bfa_lps_get_fwtag(rp->bfa, (u8)rp->rport_info.lp_tag); + m->lp_tag = rp->rport_info.lp_tag; m->local_pid = rp->rport_info.local_pid; m->fc_class = rp->rport_info.fc_class; m->vf_en = rp->rport_info.vf_en; @@ -4540,7 +4413,7 @@ bfa_rport_send_fwcreate(struct bfa_rport_s *rp) /* * queue I/O message to firmware */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT, m->mh); + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); return BFA_TRUE; } @@ -4559,13 +4432,13 @@ bfa_rport_send_fwdelete(struct bfa_rport_s *rp) } bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_DELETE_REQ, - bfa_fn_lpu(rp->bfa)); + bfa_lpuid(rp->bfa)); m->fw_handle = rp->fw_handle; /* * queue I/O message to firmware */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT, m->mh); + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); return BFA_TRUE; } @@ -4584,14 +4457,14 @@ bfa_rport_send_fwspeed(struct bfa_rport_s *rp) } bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_SET_SPEED_REQ, - bfa_fn_lpu(rp->bfa)); + bfa_lpuid(rp->bfa)); m->fw_handle = rp->fw_handle; m->speed = (u8)rp->rport_info.speed; /* * queue I/O message to firmware */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT, m->mh); + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); return BFA_TRUE; } @@ -4641,18 +4514,7 @@ bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m) } } -void -bfa_rport_res_recfg(struct bfa_s *bfa, u16 num_rport_fw) -{ - struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); - struct list_head *qe; - int i; - for (i = 0; i < (mod->num_rports - num_rport_fw); i++) { - bfa_q_deq_tail(&mod->rp_free_q, &qe); - list_add_tail(qe, &mod->rp_unused_q); - } -} /* * bfa_rport_api @@ -4715,51 +4577,26 @@ bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed) * Compute and return memory needed by FCP(im) module. */ static void -bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) { - struct bfa_sgpg_mod_s *sgpg_mod = BFA_SGPG_MOD(bfa); - struct bfa_mem_kva_s *sgpg_kva = BFA_MEM_SGPG_KVA(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_sgpg, num_sgpg; - u32 sgpg_sz = sizeof(struct bfi_sgpg_s); - if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN) cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; - else if (cfg->drvcfg.num_sgpgs > BFA_SGPG_MAX) - cfg->drvcfg.num_sgpgs = BFA_SGPG_MAX; - - num_sgpg = cfg->drvcfg.num_sgpgs; - nsegs = BFI_MEM_DMA_NSEGS(num_sgpg, sgpg_sz); - per_seg_sgpg = BFI_MEM_NREQS_SEG(sgpg_sz); - - bfa_mem_dma_seg_iter(sgpg_mod, seg_ptr, nsegs, idx) { - if (num_sgpg >= per_seg_sgpg) { - num_sgpg -= per_seg_sgpg; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_sgpg * sgpg_sz); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_sgpg * sgpg_sz); - } - - /* kva memory */ - bfa_mem_kva_setup(minfo, sgpg_kva, - cfg->drvcfg.num_sgpgs * sizeof(struct bfa_sgpg_s)); + *km_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfa_sgpg_s); + *dm_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfi_sgpg_s); } + static void bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *minfo, struct bfa_pcidev_s *pcidev) { struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); + int i; struct bfa_sgpg_s *hsgpg; struct bfi_sgpg_s *sgpg; u64 align_len; - struct bfa_mem_dma_s *seg_ptr; - u32 sgpg_sz = sizeof(struct bfi_sgpg_s); - u16 i, idx, nsegs, per_seg_sgpg, num_sgpg; union { u64 pa; @@ -4771,45 +4608,39 @@ bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_trc(bfa, cfg->drvcfg.num_sgpgs); - mod->free_sgpgs = mod->num_sgpgs = cfg->drvcfg.num_sgpgs; - - num_sgpg = cfg->drvcfg.num_sgpgs; - nsegs = BFI_MEM_DMA_NSEGS(num_sgpg, sgpg_sz); - - /* dma/kva mem claim */ - hsgpg = (struct bfa_sgpg_s *) bfa_mem_kva_curp(mod); - - bfa_mem_dma_seg_iter(mod, seg_ptr, nsegs, idx) { - - if (!bfa_mem_dma_virt(seg_ptr)) - break; - - align_len = BFA_SGPG_ROUNDUP(bfa_mem_dma_phys(seg_ptr)) - - bfa_mem_dma_phys(seg_ptr); - - sgpg = (struct bfi_sgpg_s *) - (((u8 *) bfa_mem_dma_virt(seg_ptr)) + align_len); - sgpg_pa.pa = bfa_mem_dma_phys(seg_ptr) + align_len; - WARN_ON(sgpg_pa.pa & (sgpg_sz - 1)); - - per_seg_sgpg = (seg_ptr->mem_len - (u32)align_len) / sgpg_sz; - - for (i = 0; num_sgpg > 0 && i < per_seg_sgpg; i++, num_sgpg--) { - memset(hsgpg, 0, sizeof(*hsgpg)); - memset(sgpg, 0, sizeof(*sgpg)); - - hsgpg->sgpg = sgpg; - sgpg_pa_tmp.pa = bfa_sgaddr_le(sgpg_pa.pa); - hsgpg->sgpg_pa = sgpg_pa_tmp.addr; - list_add_tail(&hsgpg->qe, &mod->sgpg_q); - - sgpg++; - hsgpg++; - sgpg_pa.pa += sgpg_sz; - } + mod->num_sgpgs = cfg->drvcfg.num_sgpgs; + mod->sgpg_arr_pa = bfa_meminfo_dma_phys(minfo); + align_len = (BFA_SGPG_ROUNDUP(mod->sgpg_arr_pa) - mod->sgpg_arr_pa); + mod->sgpg_arr_pa += align_len; + mod->hsgpg_arr = (struct bfa_sgpg_s *) (bfa_meminfo_kva(minfo) + + align_len); + mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) + + align_len); + + hsgpg = mod->hsgpg_arr; + sgpg = mod->sgpg_arr; + sgpg_pa.pa = mod->sgpg_arr_pa; + mod->free_sgpgs = mod->num_sgpgs; + + WARN_ON(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1)); + + for (i = 0; i < mod->num_sgpgs; i++) { + memset(hsgpg, 0, sizeof(*hsgpg)); + memset(sgpg, 0, sizeof(*sgpg)); + + hsgpg->sgpg = sgpg; + sgpg_pa_tmp.pa = bfa_sgaddr_le(sgpg_pa.pa); + hsgpg->sgpg_pa = sgpg_pa_tmp.addr; + list_add_tail(&hsgpg->qe, &mod->sgpg_q); + + hsgpg++; + sgpg++; + sgpg_pa.pa += sizeof(struct bfi_sgpg_s); } - bfa_mem_kva_curp(mod) = (u8 *) hsgpg; + bfa_meminfo_kva(minfo) = (u8 *) hsgpg; + bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg; + bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa; } static void @@ -4951,13 +4782,31 @@ __bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete) } static void -claim_uf_post_msgs(struct bfa_uf_mod_s *ufm) +claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) +{ + u32 uf_pb_tot_sz; + + ufm->uf_pbs_kva = (struct bfa_uf_buf_s *) bfa_meminfo_dma_virt(mi); + ufm->uf_pbs_pa = bfa_meminfo_dma_phys(mi); + uf_pb_tot_sz = BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * ufm->num_ufs), + BFA_DMA_ALIGN_SZ); + + bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz; + bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz; + + memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz); +} + +static void +claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) { struct bfi_uf_buf_post_s *uf_bp_msg; + struct bfi_sge_s *sge; + union bfi_addr_u sga_zero = { {0} }; u16 i; u16 buf_len; - ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_mem_kva_curp(ufm); + ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_meminfo_kva(mi); uf_bp_msg = ufm->uf_buf_posts; for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs; @@ -4968,18 +4817,28 @@ claim_uf_post_msgs(struct bfa_uf_mod_s *ufm) buf_len = sizeof(struct bfa_uf_buf_s); uf_bp_msg->buf_len = cpu_to_be16(buf_len); bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST, - bfa_fn_lpu(ufm->bfa)); - bfa_alen_set(&uf_bp_msg->alen, buf_len, ufm_pbs_pa(ufm, i)); + bfa_lpuid(ufm->bfa)); + + sge = uf_bp_msg->sge; + sge[0].sg_len = buf_len; + sge[0].flags = BFI_SGE_DATA_LAST; + bfa_dma_addr_set(sge[0].sga, ufm_pbs_pa(ufm, i)); + bfa_sge_to_be(sge); + + sge[1].sg_len = buf_len; + sge[1].flags = BFI_SGE_PGDLEN; + sge[1].sga = sga_zero; + bfa_sge_to_be(&sge[1]); } /* * advance pointer beyond consumed memory */ - bfa_mem_kva_curp(ufm) = (u8 *) uf_bp_msg; + bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg; } static void -claim_ufs(struct bfa_uf_mod_s *ufm) +claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) { u16 i; struct bfa_uf_s *uf; @@ -4987,7 +4846,7 @@ claim_ufs(struct bfa_uf_mod_s *ufm) /* * Claim block of memory for UF list */ - ufm->uf_list = (struct bfa_uf_s *) bfa_mem_kva_curp(ufm); + ufm->uf_list = (struct bfa_uf_s *) bfa_meminfo_kva(mi); /* * Initialize UFs and queue it in UF free queue @@ -4996,8 +4855,8 @@ claim_ufs(struct bfa_uf_mod_s *ufm) memset(uf, 0, sizeof(struct bfa_uf_s)); uf->bfa = ufm->bfa; uf->uf_tag = i; - uf->pb_len = BFA_PER_UF_DMA_SZ; - uf->buf_kva = bfa_mem_get_dmabuf_kva(ufm, i, BFA_PER_UF_DMA_SZ); + uf->pb_len = sizeof(struct bfa_uf_buf_s); + uf->buf_kva = (void *)&ufm->uf_pbs_kva[i]; uf->buf_pa = ufm_pbs_pa(ufm, i); list_add_tail(&uf->qe, &ufm->uf_free_q); } @@ -5005,57 +4864,48 @@ claim_ufs(struct bfa_uf_mod_s *ufm) /* * advance memory pointer */ - bfa_mem_kva_curp(ufm) = (u8 *) uf; + bfa_meminfo_kva(mi) = (u8 *) uf; } static void -uf_mem_claim(struct bfa_uf_mod_s *ufm) +uf_mem_claim(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) { - claim_ufs(ufm); - claim_uf_post_msgs(ufm); + claim_uf_pbs(ufm, mi); + claim_ufs(ufm, mi); + claim_uf_post_msgs(ufm, mi); } static void -bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) +bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) { - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - struct bfa_mem_kva_s *uf_kva = BFA_MEM_UF_KVA(bfa); - u32 num_ufs = cfg->fwcfg.num_uf_bufs; - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_uf = 0; - - nsegs = BFI_MEM_DMA_NSEGS(num_ufs, BFA_PER_UF_DMA_SZ); - per_seg_uf = BFI_MEM_NREQS_SEG(BFA_PER_UF_DMA_SZ); - - bfa_mem_dma_seg_iter(ufm, seg_ptr, nsegs, idx) { - if (num_ufs >= per_seg_uf) { - num_ufs -= per_seg_uf; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_uf * BFA_PER_UF_DMA_SZ); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_ufs * BFA_PER_UF_DMA_SZ); - } + u32 num_ufs = cfg->fwcfg.num_uf_bufs; - /* kva memory */ - bfa_mem_kva_setup(minfo, uf_kva, cfg->fwcfg.num_uf_bufs * - (sizeof(struct bfa_uf_s) + sizeof(struct bfi_uf_buf_post_s))); + /* + * dma-able memory for UF posted bufs + */ + *dm_len += BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * num_ufs), + BFA_DMA_ALIGN_SZ); + + /* + * kernel Virtual memory for UFs and UF buf post msg copies + */ + *ndm_len += sizeof(struct bfa_uf_s) * num_ufs; + *ndm_len += sizeof(struct bfi_uf_buf_post_s) * num_ufs; } static void bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); + memset(ufm, 0, sizeof(struct bfa_uf_mod_s)); ufm->bfa = bfa; ufm->num_ufs = cfg->fwcfg.num_uf_bufs; INIT_LIST_HEAD(&ufm->uf_free_q); INIT_LIST_HEAD(&ufm->uf_posted_q); - INIT_LIST_HEAD(&ufm->uf_unused_q); - uf_mem_claim(ufm); + uf_mem_claim(ufm, meminfo); } static void @@ -5089,7 +4939,7 @@ bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf) memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag], sizeof(struct bfi_uf_buf_post_s)); - bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP, uf_post_msg->mh); + bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP); bfa_trc(ufm->bfa, uf->uf_tag); @@ -5113,15 +4963,11 @@ uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) { struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); u16 uf_tag = m->buf_tag; + struct bfa_uf_buf_s *uf_buf = &ufm->uf_pbs_kva[uf_tag]; struct bfa_uf_s *uf = &ufm->uf_list[uf_tag]; - struct bfa_uf_buf_s *uf_buf; - uint8_t *buf; + u8 *buf = &uf_buf->d[0]; struct fchs_s *fchs; - uf_buf = (struct bfa_uf_buf_s *) - bfa_mem_get_dmabuf_kva(ufm, uf_tag, uf->pb_len); - buf = &uf_buf->d[0]; - m->frm_len = be16_to_cpu(m->frm_len); m->xfr_len = be16_to_cpu(m->xfr_len); @@ -5162,9 +5008,6 @@ bfa_uf_iocdisable(struct bfa_s *bfa) struct bfa_uf_s *uf; struct list_head *qe, *qen; - /* Enqueue unused uf resources to free_q */ - list_splice_tail_init(&ufm->uf_unused_q, &ufm->uf_free_q); - list_for_each_safe(qe, qen, &ufm->uf_posted_q) { uf = (struct bfa_uf_s *) qe; list_del(&uf->qe); @@ -5229,415 +5072,4 @@ bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) } } -void -bfa_uf_res_recfg(struct bfa_s *bfa, u16 num_uf_fw) -{ - struct bfa_uf_mod_s *mod = BFA_UF_MOD(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (mod->num_ufs - num_uf_fw); i++) { - bfa_q_deq_tail(&mod->uf_free_q, &qe); - list_add_tail(qe, &mod->uf_unused_q); - } -} - -/* - * BFA fcdiag module - */ -#define BFA_DIAG_QTEST_TOV 1000 /* msec */ - -/* - * Set port status to busy - */ -static void -bfa_fcdiag_set_busy_status(struct bfa_fcdiag_s *fcdiag) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fcdiag->bfa); - - if (fcdiag->lb.lock) - fcport->diag_busy = BFA_TRUE; - else - fcport->diag_busy = BFA_FALSE; -} - -static void -bfa_fcdiag_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - fcdiag->bfa = bfa; - fcdiag->trcmod = bfa->trcmod; - /* The common DIAG attach bfa_diag_attach() will do all memory claim */ -} - -static void -bfa_fcdiag_iocdisable(struct bfa_s *bfa) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - bfa_trc(fcdiag, fcdiag->lb.lock); - if (fcdiag->lb.lock) { - fcdiag->lb.status = BFA_STATUS_IOC_FAILURE; - fcdiag->lb.cbfn(fcdiag->lb.cbarg, fcdiag->lb.status); - fcdiag->lb.lock = 0; - bfa_fcdiag_set_busy_status(fcdiag); - } -} - -static void -bfa_fcdiag_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_start(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_queuetest_timeout(void *cbarg) -{ - struct bfa_fcdiag_s *fcdiag = cbarg; - struct bfa_diag_qtest_result_s *res = fcdiag->qtest.result; - - bfa_trc(fcdiag, fcdiag->qtest.all); - bfa_trc(fcdiag, fcdiag->qtest.count); - - fcdiag->qtest.timer_active = 0; - - res->status = BFA_STATUS_ETIMER; - res->count = QTEST_CNT_DEFAULT - fcdiag->qtest.count; - if (fcdiag->qtest.all) - res->queue = fcdiag->qtest.all; - - bfa_trc(fcdiag, BFA_STATUS_ETIMER); - fcdiag->qtest.status = BFA_STATUS_ETIMER; - fcdiag->qtest.cbfn(fcdiag->qtest.cbarg, fcdiag->qtest.status); - fcdiag->qtest.lock = 0; -} - -static bfa_status_t -bfa_fcdiag_queuetest_send(struct bfa_fcdiag_s *fcdiag) -{ - u32 i; - struct bfi_diag_qtest_req_s *req; - - req = bfa_reqq_next(fcdiag->bfa, fcdiag->qtest.queue); - if (!req) - return BFA_STATUS_DEVBUSY; - - /* build host command */ - bfi_h2i_set(req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_QTEST, - bfa_fn_lpu(fcdiag->bfa)); - - for (i = 0; i < BFI_LMSG_PL_WSZ; i++) - req->data[i] = QTEST_PAT_DEFAULT; - - bfa_trc(fcdiag, fcdiag->qtest.queue); - /* ring door bell */ - bfa_reqq_produce(fcdiag->bfa, fcdiag->qtest.queue, req->mh); - return BFA_STATUS_OK; -} - -static void -bfa_fcdiag_queuetest_comp(struct bfa_fcdiag_s *fcdiag, - bfi_diag_qtest_rsp_t *rsp) -{ - struct bfa_diag_qtest_result_s *res = fcdiag->qtest.result; - bfa_status_t status = BFA_STATUS_OK; - int i; - - /* Check timer, should still be active */ - if (!fcdiag->qtest.timer_active) { - bfa_trc(fcdiag, fcdiag->qtest.timer_active); - return; - } - - /* update count */ - fcdiag->qtest.count--; - - /* Check result */ - for (i = 0; i < BFI_LMSG_PL_WSZ; i++) { - if (rsp->data[i] != ~(QTEST_PAT_DEFAULT)) { - res->status = BFA_STATUS_DATACORRUPTED; - break; - } - } - - if (res->status == BFA_STATUS_OK) { - if (fcdiag->qtest.count > 0) { - status = bfa_fcdiag_queuetest_send(fcdiag); - if (status == BFA_STATUS_OK) - return; - else - res->status = status; - } else if (fcdiag->qtest.all > 0 && - fcdiag->qtest.queue < (BFI_IOC_MAX_CQS - 1)) { - fcdiag->qtest.count = QTEST_CNT_DEFAULT; - fcdiag->qtest.queue++; - status = bfa_fcdiag_queuetest_send(fcdiag); - if (status == BFA_STATUS_OK) - return; - else - res->status = status; - } - } - - /* Stop timer when we comp all queue */ - if (fcdiag->qtest.timer_active) { - bfa_timer_stop(&fcdiag->qtest.timer); - fcdiag->qtest.timer_active = 0; - } - res->queue = fcdiag->qtest.queue; - res->count = QTEST_CNT_DEFAULT - fcdiag->qtest.count; - bfa_trc(fcdiag, res->count); - bfa_trc(fcdiag, res->status); - fcdiag->qtest.status = res->status; - fcdiag->qtest.cbfn(fcdiag->qtest.cbarg, fcdiag->qtest.status); - fcdiag->qtest.lock = 0; -} - -static void -bfa_fcdiag_loopback_comp(struct bfa_fcdiag_s *fcdiag, - struct bfi_diag_lb_rsp_s *rsp) -{ - struct bfa_diag_loopback_result_s *res = fcdiag->lb.result; - - res->numtxmfrm = be32_to_cpu(rsp->res.numtxmfrm); - res->numosffrm = be32_to_cpu(rsp->res.numosffrm); - res->numrcvfrm = be32_to_cpu(rsp->res.numrcvfrm); - res->badfrminf = be32_to_cpu(rsp->res.badfrminf); - res->badfrmnum = be32_to_cpu(rsp->res.badfrmnum); - res->status = rsp->res.status; - fcdiag->lb.status = rsp->res.status; - bfa_trc(fcdiag, fcdiag->lb.status); - fcdiag->lb.cbfn(fcdiag->lb.cbarg, fcdiag->lb.status); - fcdiag->lb.lock = 0; - bfa_fcdiag_set_busy_status(fcdiag); -} - -static bfa_status_t -bfa_fcdiag_loopback_send(struct bfa_fcdiag_s *fcdiag, - struct bfa_diag_loopback_s *loopback) -{ - struct bfi_diag_lb_req_s *lb_req; - - lb_req = bfa_reqq_next(fcdiag->bfa, BFA_REQQ_DIAG); - if (!lb_req) - return BFA_STATUS_DEVBUSY; - - /* build host command */ - bfi_h2i_set(lb_req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_LOOPBACK, - bfa_fn_lpu(fcdiag->bfa)); - - lb_req->lb_mode = loopback->lb_mode; - lb_req->speed = loopback->speed; - lb_req->loopcnt = loopback->loopcnt; - lb_req->pattern = loopback->pattern; - - /* ring door bell */ - bfa_reqq_produce(fcdiag->bfa, BFA_REQQ_DIAG, lb_req->mh); - - bfa_trc(fcdiag, loopback->lb_mode); - bfa_trc(fcdiag, loopback->speed); - bfa_trc(fcdiag, loopback->loopcnt); - bfa_trc(fcdiag, loopback->pattern); - return BFA_STATUS_OK; -} - -/* - * cpe/rme intr handler - */ -void -bfa_fcdiag_intr(struct bfa_s *bfa, struct bfi_msg_s *msg) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - - switch (msg->mhdr.msg_id) { - case BFI_DIAG_I2H_LOOPBACK: - bfa_fcdiag_loopback_comp(fcdiag, - (struct bfi_diag_lb_rsp_s *) msg); - break; - case BFI_DIAG_I2H_QTEST: - bfa_fcdiag_queuetest_comp(fcdiag, (bfi_diag_qtest_rsp_t *)msg); - break; - default: - bfa_trc(fcdiag, msg->mhdr.msg_id); - WARN_ON(1); - } -} - -/* - * Loopback test - * - * @param[in] *bfa - bfa data struct - * @param[in] opmode - port operation mode - * @param[in] speed - port speed - * @param[in] lpcnt - loop count - * @param[in] pat - pattern to build packet - * @param[in] *result - pt to bfa_diag_loopback_result_t data struct - * @param[in] cbfn - callback function - * @param[in] cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_fcdiag_loopback(struct bfa_s *bfa, enum bfa_port_opmode opmode, - enum bfa_port_speed speed, u32 lpcnt, u32 pat, - struct bfa_diag_loopback_result_s *result, bfa_cb_diag_t cbfn, - void *cbarg) -{ - struct bfa_diag_loopback_s loopback; - struct bfa_port_attr_s attr; - bfa_status_t status; - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - - if (!bfa_iocfc_is_operational(bfa)) - return BFA_STATUS_IOC_NON_OP; - - /* if port is PBC disabled, return error */ - if (bfa_fcport_is_pbcdisabled(bfa)) { - bfa_trc(fcdiag, BFA_STATUS_PBC); - return BFA_STATUS_PBC; - } - if (bfa_fcport_is_disabled(bfa) == BFA_FALSE) { - bfa_trc(fcdiag, opmode); - return BFA_STATUS_PORT_NOT_DISABLED; - } - - /* Check if the speed is supported */ - bfa_fcport_get_attr(bfa, &attr); - bfa_trc(fcdiag, attr.speed_supported); - if (speed > attr.speed_supported) - return BFA_STATUS_UNSUPP_SPEED; - - /* For Mezz card, port speed entered needs to be checked */ - if (bfa_mfg_is_mezz(bfa->ioc.attr->card_type)) { - if (bfa_ioc_get_type(&bfa->ioc) == BFA_IOC_TYPE_FC) { - if ((speed == BFA_PORT_SPEED_1GBPS) && - (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id))) - return BFA_STATUS_UNSUPP_SPEED; - if (!(speed == BFA_PORT_SPEED_1GBPS || - speed == BFA_PORT_SPEED_2GBPS || - speed == BFA_PORT_SPEED_4GBPS || - speed == BFA_PORT_SPEED_8GBPS || - speed == BFA_PORT_SPEED_16GBPS || - speed == BFA_PORT_SPEED_AUTO)) - return BFA_STATUS_UNSUPP_SPEED; - } else { - if (speed != BFA_PORT_SPEED_10GBPS) - return BFA_STATUS_UNSUPP_SPEED; - } - } - - /* check to see if there is another destructive diag cmd running */ - if (fcdiag->lb.lock) { - bfa_trc(fcdiag, fcdiag->lb.lock); - return BFA_STATUS_DEVBUSY; - } - - fcdiag->lb.lock = 1; - loopback.lb_mode = opmode; - loopback.speed = speed; - loopback.loopcnt = lpcnt; - loopback.pattern = pat; - fcdiag->lb.result = result; - fcdiag->lb.cbfn = cbfn; - fcdiag->lb.cbarg = cbarg; - memset(result, 0, sizeof(struct bfa_diag_loopback_result_s)); - bfa_fcdiag_set_busy_status(fcdiag); - - /* Send msg to fw */ - status = bfa_fcdiag_loopback_send(fcdiag, &loopback); - return status; -} - -/* - * DIAG queue test command - * - * @param[in] *bfa - bfa data struct - * @param[in] force - 1: don't do ioc op checking - * @param[in] queue - queue no. to test - * @param[in] *result - pt to bfa_diag_qtest_result_t data struct - * @param[in] cbfn - callback function - * @param[in] *cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_fcdiag_queuetest(struct bfa_s *bfa, u32 force, u32 queue, - struct bfa_diag_qtest_result_s *result, bfa_cb_diag_t cbfn, - void *cbarg) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - bfa_status_t status; - bfa_trc(fcdiag, force); - bfa_trc(fcdiag, queue); - - if (!force && !bfa_iocfc_is_operational(bfa)) - return BFA_STATUS_IOC_NON_OP; - - /* check to see if there is another destructive diag cmd running */ - if (fcdiag->qtest.lock) { - bfa_trc(fcdiag, fcdiag->qtest.lock); - return BFA_STATUS_DEVBUSY; - } - - /* Initialization */ - fcdiag->qtest.lock = 1; - fcdiag->qtest.cbfn = cbfn; - fcdiag->qtest.cbarg = cbarg; - fcdiag->qtest.result = result; - fcdiag->qtest.count = QTEST_CNT_DEFAULT; - - /* Init test results */ - fcdiag->qtest.result->status = BFA_STATUS_OK; - fcdiag->qtest.result->count = 0; - - /* send */ - if (queue < BFI_IOC_MAX_CQS) { - fcdiag->qtest.result->queue = (u8)queue; - fcdiag->qtest.queue = (u8)queue; - fcdiag->qtest.all = 0; - } else { - fcdiag->qtest.result->queue = 0; - fcdiag->qtest.queue = 0; - fcdiag->qtest.all = 1; - } - status = bfa_fcdiag_queuetest_send(fcdiag); - - /* Start a timer */ - if (status == BFA_STATUS_OK) { - bfa_timer_start(bfa, &fcdiag->qtest.timer, - bfa_fcdiag_queuetest_timeout, fcdiag, - BFA_DIAG_QTEST_TOV); - fcdiag->qtest.timer_active = 1; - } - return status; -} - -/* - * DIAG PLB is running - * - * @param[in] *bfa - bfa data struct - * - * @param[out] - */ -bfa_status_t -bfa_fcdiag_lb_is_running(struct bfa_s *bfa) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - return fcdiag->lb.lock ? BFA_STATUS_DIAG_BUSY : BFA_STATUS_OK; -} diff --git a/trunk/drivers/scsi/bfa/bfa_svc.h b/trunk/drivers/scsi/bfa/bfa_svc.h index fbe513a671b5..5902a45c080f 100644 --- a/trunk/drivers/scsi/bfa/bfa_svc.h +++ b/trunk/drivers/scsi/bfa/bfa_svc.h @@ -26,7 +26,6 @@ * Scatter-gather DMA related defines */ #define BFA_SGPG_MIN (16) -#define BFA_SGPG_MAX (8192) /* * Alignment macro for SG page allocation @@ -55,21 +54,17 @@ struct bfa_sgpg_s { */ #define BFA_SGPG_NPAGE(_nsges) (((_nsges) / BFI_SGPG_DATA_SGES) + 1) -/* Max SGPG dma segs required */ -#define BFA_SGPG_DMA_SEGS \ - BFI_MEM_DMA_NSEGS(BFA_SGPG_MAX, (uint32_t)sizeof(struct bfi_sgpg_s)) - struct bfa_sgpg_mod_s { struct bfa_s *bfa; int num_sgpgs; /* number of SG pages */ int free_sgpgs; /* number of free SG pages */ + struct bfa_sgpg_s *hsgpg_arr; /* BFA SG page array */ + struct bfi_sgpg_s *sgpg_arr; /* actual SG page array */ + u64 sgpg_arr_pa; /* SG page array DMA addr */ struct list_head sgpg_q; /* queue of free SG pages */ struct list_head sgpg_wait_q; /* wait queue for SG pages */ - struct bfa_mem_dma_s dma_seg[BFA_SGPG_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; }; #define BFA_SGPG_MOD(__bfa) (&(__bfa)->modules.sgpg_mod) -#define BFA_MEM_SGPG_KVA(__bfa) (&(BFA_SGPG_MOD(__bfa)->kva_seg)) bfa_status_t bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs); @@ -84,32 +79,26 @@ void bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe); * FCXP related defines */ #define BFA_FCXP_MIN (1) -#define BFA_FCXP_MAX (256) #define BFA_FCXP_MAX_IBUF_SZ (2 * 1024 + 256) #define BFA_FCXP_MAX_LBUF_SZ (4 * 1024 + 256) -/* Max FCXP dma segs required */ -#define BFA_FCXP_DMA_SEGS \ - BFI_MEM_DMA_NSEGS(BFA_FCXP_MAX, \ - (u32)BFA_FCXP_MAX_IBUF_SZ + BFA_FCXP_MAX_LBUF_SZ) - struct bfa_fcxp_mod_s { struct bfa_s *bfa; /* backpointer to BFA */ struct bfa_fcxp_s *fcxp_list; /* array of FCXPs */ u16 num_fcxps; /* max num FCXP requests */ struct list_head fcxp_free_q; /* free FCXPs */ struct list_head fcxp_active_q; /* active FCXPs */ + void *req_pld_list_kva; /* list of FCXP req pld */ + u64 req_pld_list_pa; /* list of FCXP req pld */ + void *rsp_pld_list_kva; /* list of FCXP resp pld */ + u64 rsp_pld_list_pa; /* list of FCXP resp pld */ struct list_head wait_q; /* wait queue for free fcxp */ - struct list_head fcxp_unused_q; /* unused fcxps */ u32 req_pld_sz; u32 rsp_pld_sz; - struct bfa_mem_dma_s dma_seg[BFA_FCXP_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; }; #define BFA_FCXP_MOD(__bfa) (&(__bfa)->modules.fcxp_mod) #define BFA_FCXP_FROM_TAG(__mod, __tag) (&(__mod)->fcxp_list[__tag]) -#define BFA_MEM_FCXP_KVA(__bfa) (&(BFA_FCXP_MOD(__bfa)->kva_seg)) typedef void (*fcxp_send_cb_t) (struct bfa_s *ioc, struct bfa_fcxp_s *fcxp, void *cb_arg, bfa_status_t req_status, @@ -217,15 +206,13 @@ struct bfa_fcxp_wqe_s { #define BFA_FCXP_RSP_FCHS(_fcxp) (&((_fcxp)->rsp_info.fchs)) #define BFA_FCXP_RSP_PLD(_fcxp) (bfa_fcxp_get_rspbuf(_fcxp)) -#define BFA_FCXP_REQ_PLD_PA(_fcxp) \ - bfa_mem_get_dmabuf_pa((_fcxp)->fcxp_mod, (_fcxp)->fcxp_tag, \ - (_fcxp)->fcxp_mod->req_pld_sz + (_fcxp)->fcxp_mod->rsp_pld_sz) +#define BFA_FCXP_REQ_PLD_PA(_fcxp) \ + ((_fcxp)->fcxp_mod->req_pld_list_pa + \ + ((_fcxp)->fcxp_mod->req_pld_sz * (_fcxp)->fcxp_tag)) -/* fcxp_buf = req_buf + rsp_buf :- add req_buf_sz to get to rsp_buf */ -#define BFA_FCXP_RSP_PLD_PA(_fcxp) \ - (bfa_mem_get_dmabuf_pa((_fcxp)->fcxp_mod, (_fcxp)->fcxp_tag, \ - (_fcxp)->fcxp_mod->req_pld_sz + (_fcxp)->fcxp_mod->rsp_pld_sz) + \ - (_fcxp)->fcxp_mod->req_pld_sz) +#define BFA_FCXP_RSP_PLD_PA(_fcxp) \ + ((_fcxp)->fcxp_mod->rsp_pld_list_pa + \ + ((_fcxp)->fcxp_mod->rsp_pld_sz * (_fcxp)->fcxp_tag)) void bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); @@ -251,13 +238,10 @@ struct bfa_rport_mod_s { struct bfa_rport_s *rps_list; /* list of rports */ struct list_head rp_free_q; /* free bfa_rports */ struct list_head rp_active_q; /* free bfa_rports */ - struct list_head rp_unused_q; /* unused bfa rports */ u16 num_rports; /* number of rports */ - struct bfa_mem_kva_s kva_seg; }; #define BFA_RPORT_MOD(__bfa) (&(__bfa)->modules.rport_mod) -#define BFA_MEM_RPORT_KVA(__bfa) (&(BFA_RPORT_MOD(__bfa)->kva_seg)) /* * Convert rport tag to RPORT @@ -270,7 +254,6 @@ struct bfa_rport_mod_s { * protected functions */ void bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_rport_res_recfg(struct bfa_s *bfa, u16 num_rport_fw); /* * BFA rport information. @@ -315,7 +298,7 @@ struct bfa_rport_s { */ #define BFA_UF_MIN (4) -#define BFA_UF_MAX (256) + struct bfa_uf_s { struct list_head qe; /* queue element */ @@ -343,41 +326,36 @@ struct bfa_uf_s { */ typedef void (*bfa_cb_uf_recv_t) (void *cbarg, struct bfa_uf_s *uf); -#define BFA_UF_BUFSZ (2 * 1024 + 256) - -struct bfa_uf_buf_s { - u8 d[BFA_UF_BUFSZ]; -}; - -#define BFA_PER_UF_DMA_SZ \ - (u32)BFA_ROUNDUP(sizeof(struct bfa_uf_buf_s), BFA_DMA_ALIGN_SZ) - -/* Max UF dma segs required */ -#define BFA_UF_DMA_SEGS BFI_MEM_DMA_NSEGS(BFA_UF_MAX, BFA_PER_UF_DMA_SZ) - struct bfa_uf_mod_s { struct bfa_s *bfa; /* back pointer to BFA */ struct bfa_uf_s *uf_list; /* array of UFs */ u16 num_ufs; /* num unsolicited rx frames */ struct list_head uf_free_q; /* free UFs */ struct list_head uf_posted_q; /* UFs posted to IOC */ - struct list_head uf_unused_q; /* unused UF's */ + struct bfa_uf_buf_s *uf_pbs_kva; /* list UF bufs request pld */ + u64 uf_pbs_pa; /* phy addr for UF bufs */ struct bfi_uf_buf_post_s *uf_buf_posts; /* pre-built UF post msgs */ bfa_cb_uf_recv_t ufrecv; /* uf recv handler function */ void *cbarg; /* uf receive handler arg */ - struct bfa_mem_dma_s dma_seg[BFA_UF_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; }; #define BFA_UF_MOD(__bfa) (&(__bfa)->modules.uf_mod) -#define BFA_MEM_UF_KVA(__bfa) (&(BFA_UF_MOD(__bfa)->kva_seg)) #define ufm_pbs_pa(_ufmod, _uftag) \ - bfa_mem_get_dmabuf_pa(_ufmod, _uftag, BFA_PER_UF_DMA_SZ) + ((_ufmod)->uf_pbs_pa + sizeof(struct bfa_uf_buf_s) * (_uftag)) void bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_uf_res_recfg(struct bfa_s *bfa, u16 num_uf_fw); + +#define BFA_UF_BUFSZ (2 * 1024 + 256) + +/* + * @todo private + */ +struct bfa_uf_buf_s { + u8 d[BFA_UF_BUFSZ]; +}; + /* * LPS - bfa lport login/logout service interface @@ -386,8 +364,7 @@ struct bfa_lps_s { struct list_head qe; /* queue element */ struct bfa_s *bfa; /* parent bfa instance */ bfa_sm_t sm; /* finite state machine */ - u8 bfa_tag; /* lport tag */ - u8 fw_tag; /* lport fw tag */ + u8 lp_tag; /* lport tag */ u8 reqq; /* lport request queue */ u8 alpa; /* ALPA for loop topologies */ u32 lp_pid; /* lport port ID */ @@ -400,8 +377,6 @@ struct bfa_lps_s { bfa_status_t status; /* login status */ u16 pdusz; /* max receive PDU size */ u16 pr_bbcred; /* BB_CREDIT from peer */ - u8 pr_bbscn; /* BB_SCN from peer */ - u8 bb_scn; /* local BB_SCN */ u8 lsrjt_rsn; /* LSRJT reason */ u8 lsrjt_expl; /* LSRJT explanation */ wwn_t pwwn; /* port wwn of lport */ @@ -420,15 +395,12 @@ struct bfa_lps_s { struct bfa_lps_mod_s { struct list_head lps_free_q; struct list_head lps_active_q; - struct list_head lps_login_q; struct bfa_lps_s *lps_arr; int num_lps; - struct bfa_mem_kva_s kva_seg; }; #define BFA_LPS_MOD(__bfa) (&(__bfa)->modules.lps_mod) #define BFA_LPS_FROM_TAG(__mod, __tag) (&(__mod)->lps_arr[__tag]) -#define BFA_MEM_LPS_KVA(__bfa) (&(BFA_LPS_MOD(__bfa)->kva_seg)) /* * external functions @@ -505,14 +477,11 @@ struct bfa_fcport_s { bfa_boolean_t diag_busy; /* diag busy status */ bfa_boolean_t beacon; /* port beacon status */ bfa_boolean_t link_e2e_beacon; /* link beacon status */ - bfa_boolean_t bbsc_op_state; /* Cred recov Oper State */ struct bfa_fcport_trunk_s trunk; u16 fcoe_vlan; - struct bfa_mem_dma_s fcport_dma; }; #define BFA_FCPORT_MOD(__bfa) (&(__bfa)->modules.fcport) -#define BFA_MEM_FCPORT_DMA(__bfa) (&(BFA_FCPORT_MOD(__bfa)->fcport_dma)) /* * protected functions @@ -546,10 +515,8 @@ void bfa_fcport_event_register(struct bfa_s *bfa, bfa_boolean_t bfa_fcport_is_disabled(struct bfa_s *bfa); enum bfa_port_speed bfa_fcport_get_ratelim_speed(struct bfa_s *bfa); -void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit, u8 bb_scn); +void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit); bfa_boolean_t bfa_fcport_is_ratelim(struct bfa_s *bfa); -void bfa_fcport_beacon(void *dev, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon); bfa_boolean_t bfa_fcport_is_linkup(struct bfa_s *bfa); bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats, @@ -557,9 +524,6 @@ bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa, bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg); bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa); -bfa_boolean_t bfa_fcport_is_trunk_enabled(struct bfa_s *bfa); -bfa_status_t bfa_fcport_is_pbcdisabled(struct bfa_s *bfa); -void bfa_fcport_cfg_faa(struct bfa_s *bfa, u8 state); /* * bfa rport API functions @@ -613,7 +577,6 @@ void bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, bfa_status_t bfa_fcxp_abort(struct bfa_fcxp_s *fcxp); u32 bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp); u32 bfa_fcxp_get_maxrsp(struct bfa_s *bfa); -void bfa_fcxp_res_recfg(struct bfa_s *bfa, u16 num_fcxp_fw); static inline void * bfa_uf_get_frmbuf(struct bfa_uf_s *uf) @@ -643,12 +606,11 @@ struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa); void bfa_lps_delete(struct bfa_lps_s *lps); void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, wwn_t pwwn, wwn_t nwwn, - bfa_boolean_t auth_en, u8 bb_scn); + bfa_boolean_t auth_en); void bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn, wwn_t nwwn); void bfa_lps_fdisclogo(struct bfa_lps_s *lps); void bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, u32 n2n_pid); -u8 bfa_lps_get_fwtag(struct bfa_s *bfa, u8 lp_tag); u32 bfa_lps_get_base_pid(struct bfa_s *bfa); u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid); void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status); @@ -656,57 +618,4 @@ void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status); void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg); void bfa_cb_lps_cvl_event(void *bfad, void *uarg); -/* FAA specific APIs */ -bfa_status_t bfa_faa_enable(struct bfa_s *bfa, - bfa_cb_iocfc_t cbfn, void *cbarg); -bfa_status_t bfa_faa_disable(struct bfa_s *bfa, - bfa_cb_iocfc_t cbfn, void *cbarg); -bfa_status_t bfa_faa_query(struct bfa_s *bfa, struct bfa_faa_attr_s *attr, - bfa_cb_iocfc_t cbfn, void *cbarg); - -/* - * FC DIAG data structure - */ -struct bfa_fcdiag_qtest_s { - struct bfa_diag_qtest_result_s *result; - bfa_cb_diag_t cbfn; - void *cbarg; - struct bfa_timer_s timer; - u32 status; - u32 count; - u8 lock; - u8 queue; - u8 all; - u8 timer_active; -}; - -struct bfa_fcdiag_lb_s { - bfa_cb_diag_t cbfn; - void *cbarg; - void *result; - bfa_boolean_t lock; - u32 status; -}; - -struct bfa_fcdiag_s { - struct bfa_s *bfa; /* Back pointer to BFA */ - struct bfa_trc_mod_s *trcmod; - struct bfa_fcdiag_lb_s lb; - struct bfa_fcdiag_qtest_s qtest; -}; - -#define BFA_FCDIAG_MOD(__bfa) (&(__bfa)->modules.fcdiag) - -void bfa_fcdiag_intr(struct bfa_s *bfa, struct bfi_msg_s *msg); - -bfa_status_t bfa_fcdiag_loopback(struct bfa_s *bfa, - enum bfa_port_opmode opmode, - enum bfa_port_speed speed, u32 lpcnt, u32 pat, - struct bfa_diag_loopback_result_s *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_fcdiag_queuetest(struct bfa_s *bfa, u32 ignore, - u32 queue, struct bfa_diag_qtest_result_s *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_fcdiag_lb_is_running(struct bfa_s *bfa); - #endif /* __BFA_SVC_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfad.c b/trunk/drivers/scsi/bfa/bfad.c index beb30a748ea5..59b5e9b61d71 100644 --- a/trunk/drivers/scsi/bfa/bfad.c +++ b/trunk/drivers/scsi/bfa/bfad.c @@ -56,15 +56,14 @@ int fdmi_enable = BFA_TRUE; int pcie_max_read_reqsz; int bfa_debugfs_enable = 1; int msix_disable_cb = 0, msix_disable_ct = 0; -int max_xfer_size = BFAD_MAX_SECTORS >> 1; /* Firmware releated */ -u32 bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size; -u32 *bfi_image_cb, *bfi_image_ct, *bfi_image_ct2; +u32 bfi_image_ct_fc_size, bfi_image_ct_cna_size, bfi_image_cb_fc_size; +u32 *bfi_image_ct_fc, *bfi_image_ct_cna, *bfi_image_cb_fc; -#define BFAD_FW_FILE_CB "cbfw.bin" -#define BFAD_FW_FILE_CT "ctfw.bin" -#define BFAD_FW_FILE_CT2 "ct2fw.bin" +#define BFAD_FW_FILE_CT_FC "ctfw_fc.bin" +#define BFAD_FW_FILE_CT_CNA "ctfw_cna.bin" +#define BFAD_FW_FILE_CB_FC "cbfw_fc.bin" static u32 *bfad_load_fwimg(struct pci_dev *pdev); static void bfad_free_fwimg(void); @@ -72,18 +71,18 @@ static void bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, u32 *bfi_image_size, char *fw_name); static const char *msix_name_ct[] = { - "ctrl", "cpe0", "cpe1", "cpe2", "cpe3", - "rme0", "rme1", "rme2", "rme3" }; + "rme0", "rme1", "rme2", "rme3", + "ctrl" }; static const char *msix_name_cb[] = { "cpe0", "cpe1", "cpe2", "cpe3", "rme0", "rme1", "rme2", "rme3", "eemc", "elpu0", "elpu1", "epss", "mlpu" }; -MODULE_FIRMWARE(BFAD_FW_FILE_CB); -MODULE_FIRMWARE(BFAD_FW_FILE_CT); -MODULE_FIRMWARE(BFAD_FW_FILE_CT2); +MODULE_FIRMWARE(BFAD_FW_FILE_CT_FC); +MODULE_FIRMWARE(BFAD_FW_FILE_CT_CNA); +MODULE_FIRMWARE(BFAD_FW_FILE_CB_FC); module_param(os_name, charp, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(os_name, "OS name of the hba host machine"); @@ -145,9 +144,6 @@ MODULE_PARM_DESC(pcie_max_read_reqsz, "PCIe max read request size, default=0 " module_param(bfa_debugfs_enable, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(bfa_debugfs_enable, "Enables debugfs feature, default=1," " Range[false:0|true:1]"); -module_param(max_xfer_size, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_xfer_size, "default=32MB," - " Range[64k|128k|256k|512k|1024k|2048k]"); static void bfad_sm_uninit(struct bfad_s *bfad, enum bfad_sm_event event); @@ -531,26 +527,28 @@ bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s pbc_vport) void bfad_hal_mem_release(struct bfad_s *bfad) { + int i; struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; - struct bfa_mem_dma_s *dma_info, *dma_elem; - struct bfa_mem_kva_s *kva_info, *kva_elem; - struct list_head *dm_qe, *km_qe; - - dma_info = &hal_meminfo->dma_info; - kva_info = &hal_meminfo->kva_info; - - /* Iterate through the KVA meminfo queue */ - list_for_each(km_qe, &kva_info->qe) { - kva_elem = (struct bfa_mem_kva_s *) km_qe; - vfree(kva_elem->kva); - } - - /* Iterate through the DMA meminfo queue */ - list_for_each(dm_qe, &dma_info->qe) { - dma_elem = (struct bfa_mem_dma_s *) dm_qe; - dma_free_coherent(&bfad->pcidev->dev, - dma_elem->mem_len, dma_elem->kva, - (dma_addr_t) dma_elem->dma); + struct bfa_mem_elem_s *meminfo_elem; + + for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { + meminfo_elem = &hal_meminfo->meminfo[i]; + if (meminfo_elem->kva != NULL) { + switch (meminfo_elem->mem_type) { + case BFA_MEM_TYPE_KVA: + vfree(meminfo_elem->kva); + break; + case BFA_MEM_TYPE_DMA: + dma_free_coherent(&bfad->pcidev->dev, + meminfo_elem->mem_len, + meminfo_elem->kva, + (dma_addr_t) meminfo_elem->dma); + break; + default: + WARN_ON(1); + break; + } + } } memset(hal_meminfo, 0, sizeof(struct bfa_meminfo_s)); @@ -565,15 +563,15 @@ bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg) bfa_cfg->fwcfg.num_ioim_reqs = num_ios; if (num_tms > 0) bfa_cfg->fwcfg.num_tskim_reqs = num_tms; - if (num_fcxps > 0 && num_fcxps <= BFA_FCXP_MAX) + if (num_fcxps > 0) bfa_cfg->fwcfg.num_fcxp_reqs = num_fcxps; - if (num_ufbufs > 0 && num_ufbufs <= BFA_UF_MAX) + if (num_ufbufs > 0) bfa_cfg->fwcfg.num_uf_bufs = num_ufbufs; if (reqq_size > 0) bfa_cfg->drvcfg.num_reqq_elems = reqq_size; if (rspq_size > 0) bfa_cfg->drvcfg.num_rspq_elems = rspq_size; - if (num_sgpgs > 0 && num_sgpgs <= BFA_SGPG_MAX) + if (num_sgpgs > 0) bfa_cfg->drvcfg.num_sgpgs = num_sgpgs; /* @@ -593,46 +591,85 @@ bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg) bfa_status_t bfad_hal_mem_alloc(struct bfad_s *bfad) { + int i; struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; - struct bfa_mem_dma_s *dma_info, *dma_elem; - struct bfa_mem_kva_s *kva_info, *kva_elem; - struct list_head *dm_qe, *km_qe; - bfa_status_t rc = BFA_STATUS_OK; + struct bfa_mem_elem_s *meminfo_elem; dma_addr_t phys_addr; + void *kva; + bfa_status_t rc = BFA_STATUS_OK; + int retry_count = 0; + int reset_value = 1; + int min_num_sgpgs = 512; bfa_cfg_get_default(&bfad->ioc_cfg); + +retry: bfad_update_hal_cfg(&bfad->ioc_cfg); bfad->cfg_data.ioc_queue_depth = bfad->ioc_cfg.fwcfg.num_ioim_reqs; - bfa_cfg_get_meminfo(&bfad->ioc_cfg, hal_meminfo, &bfad->bfa); - - dma_info = &hal_meminfo->dma_info; - kva_info = &hal_meminfo->kva_info; - - /* Iterate through the KVA meminfo queue */ - list_for_each(km_qe, &kva_info->qe) { - kva_elem = (struct bfa_mem_kva_s *) km_qe; - kva_elem->kva = vmalloc(kva_elem->mem_len); - if (kva_elem->kva == NULL) { - bfad_hal_mem_release(bfad); - rc = BFA_STATUS_ENOMEM; - goto ext; - } - memset(kva_elem->kva, 0, kva_elem->mem_len); - } + bfa_cfg_get_meminfo(&bfad->ioc_cfg, hal_meminfo); + + for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { + meminfo_elem = &hal_meminfo->meminfo[i]; + switch (meminfo_elem->mem_type) { + case BFA_MEM_TYPE_KVA: + kva = vmalloc(meminfo_elem->mem_len); + if (kva == NULL) { + bfad_hal_mem_release(bfad); + rc = BFA_STATUS_ENOMEM; + goto ext; + } + memset(kva, 0, meminfo_elem->mem_len); + meminfo_elem->kva = kva; + break; + case BFA_MEM_TYPE_DMA: + kva = dma_alloc_coherent(&bfad->pcidev->dev, + meminfo_elem->mem_len, &phys_addr, GFP_KERNEL); + if (kva == NULL) { + bfad_hal_mem_release(bfad); + /* + * If we cannot allocate with default + * num_sgpages try with half the value. + */ + if (num_sgpgs > min_num_sgpgs) { + printk(KERN_INFO + "bfad[%d]: memory allocation failed" + " with num_sgpgs: %d\n", + bfad->inst_no, num_sgpgs); + nextLowerInt(&num_sgpgs); + printk(KERN_INFO + "bfad[%d]: trying to allocate memory" + " with num_sgpgs: %d\n", + bfad->inst_no, num_sgpgs); + retry_count++; + goto retry; + } else { + if (num_sgpgs_parm > 0) + num_sgpgs = num_sgpgs_parm; + else { + reset_value = + (1 << retry_count); + num_sgpgs *= reset_value; + } + rc = BFA_STATUS_ENOMEM; + goto ext; + } + } + + if (num_sgpgs_parm > 0) + num_sgpgs = num_sgpgs_parm; + else { + reset_value = (1 << retry_count); + num_sgpgs *= reset_value; + } + + memset(kva, 0, meminfo_elem->mem_len); + meminfo_elem->kva = kva; + meminfo_elem->dma = phys_addr; + break; + default: + break; - /* Iterate through the DMA meminfo queue */ - list_for_each(dm_qe, &dma_info->qe) { - dma_elem = (struct bfa_mem_dma_s *) dm_qe; - dma_elem->kva = dma_alloc_coherent(&bfad->pcidev->dev, - dma_elem->mem_len, - &phys_addr, GFP_KERNEL); - if (dma_elem->kva == NULL) { - bfad_hal_mem_release(bfad); - rc = BFA_STATUS_ENOMEM; - goto ext; } - dma_elem->dma = phys_addr; - memset(dma_elem->kva, 0, dma_elem->mem_len); } ext: return rc; @@ -743,17 +780,13 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) pci_set_master(pdev); - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || - (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) || - (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)) { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { printk(KERN_ERR "pci_set_dma_mask fail %p\n", pdev); goto out_release_region; } - } bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); - bfad->pci_bar2_kva = pci_iomap(pdev, 2, pci_resource_len(pdev, 2)); if (bfad->pci_bar0_kva == NULL) { printk(KERN_ERR "Fail to map bar0\n"); @@ -764,7 +797,6 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) bfad->hal_pcidev.pci_func = PCI_FUNC(pdev->devfn); bfad->hal_pcidev.pci_bar_kva = bfad->pci_bar0_kva; bfad->hal_pcidev.device_id = pdev->device; - bfad->hal_pcidev.ssid = pdev->subsystem_device; bfad->pci_name = pci_name(pdev); bfad->pci_attr.vendor_id = pdev->vendor; @@ -836,7 +868,6 @@ void bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad) { pci_iounmap(pdev, bfad->pci_bar0_kva); - pci_iounmap(pdev, bfad->pci_bar2_kva); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); @@ -877,29 +908,12 @@ bfad_drv_init(struct bfad_s *bfad) bfad->bfa_fcs.trcmod = bfad->trcmod; bfa_fcs_attach(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE); bfad->bfa_fcs.fdmi_enabled = fdmi_enable; - bfa_fcs_init(&bfad->bfa_fcs); spin_unlock_irqrestore(&bfad->bfad_lock, flags); bfad->bfad_flags |= BFAD_DRV_INIT_DONE; - /* configure base port */ - rc = bfad_cfg_pport(bfad, BFA_LPORT_ROLE_FCP_IM); - if (rc != BFA_STATUS_OK) - goto out_cfg_pport_fail; - return BFA_STATUS_OK; -out_cfg_pport_fail: - /* fcs exit - on cfg pport failure */ - spin_lock_irqsave(&bfad->bfad_lock, flags); - init_completion(&bfad->comp); - bfad->pport.flags |= BFAD_PORT_DELETE; - bfa_fcs_exit(&bfad->bfa_fcs); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->comp); - /* bfa detach - free hal memory */ - bfa_detach(&bfad->bfa); - bfad_hal_mem_release(bfad); out_hal_mem_alloc_failure: return BFA_STATUS_FAILED; } @@ -931,7 +945,6 @@ bfad_drv_start(struct bfad_s *bfad) spin_lock_irqsave(&bfad->bfad_lock, flags); bfa_iocfc_start(&bfad->bfa); - bfa_fcs_pbc_vport_init(&bfad->bfa_fcs); bfa_fcs_fabric_modstart(&bfad->bfa_fcs); bfad->bfad_flags |= BFAD_HAL_START_DONE; spin_unlock_irqrestore(&bfad->bfad_lock, flags); @@ -1019,12 +1032,6 @@ bfad_start_ops(struct bfad_s *bfad) { struct bfad_vport_s *vport, *vport_new; struct bfa_fcs_driver_info_s driver_info; - /* Limit min/max. xfer size to [64k-32MB] */ - if (max_xfer_size < BFAD_MIN_SECTORS >> 1) - max_xfer_size = BFAD_MIN_SECTORS >> 1; - if (max_xfer_size > BFAD_MAX_SECTORS >> 1) - max_xfer_size = BFAD_MAX_SECTORS >> 1; - /* Fill the driver_info info to fcs*/ memset(&driver_info, 0, sizeof(driver_info)); strncpy(driver_info.version, BFAD_DRIVER_VERSION, @@ -1042,19 +1049,19 @@ bfad_start_ops(struct bfad_s *bfad) { strncpy(driver_info.os_device_name, bfad->pci_name, sizeof(driver_info.os_device_name - 1)); - /* FCS driver info init */ + /* FCS INIT */ spin_lock_irqsave(&bfad->bfad_lock, flags); bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info); + bfa_fcs_init(&bfad->bfa_fcs); spin_unlock_irqrestore(&bfad->bfad_lock, flags); - /* - * FCS update cfg - reset the pwwn/nwwn of fabric base logical port - * with values learned during bfa_init firmware GETATTR REQ. - */ - bfa_fcs_update_cfg(&bfad->bfa_fcs); - - /* Setup fc host fixed attribute if the lk supports */ - bfad_fc_host_init(bfad->pport.im_port); + retval = bfad_cfg_pport(bfad, BFA_LPORT_ROLE_FCP_IM); + if (retval != BFA_STATUS_OK) { + if (bfa_sm_cmp_state(bfad, bfad_sm_initializing)) + bfa_sm_set_state(bfad, bfad_sm_failed); + bfad_stop(bfad); + return BFA_STATUS_FAILED; + } /* BFAD level FC4 IM specific resource allocation */ retval = bfad_im_probe(bfad); @@ -1226,8 +1233,8 @@ bfad_install_msix_handler(struct bfad_s *bfad) for (i = 0; i < bfad->nvec; i++) { sprintf(bfad->msix_tab[i].name, "bfa-%s-%s", bfad->pci_name, - ((bfa_asic_id_cb(bfad->hal_pcidev.device_id)) ? - msix_name_cb[i] : msix_name_ct[i])); + ((bfa_asic_id_ct(bfad->hal_pcidev.device_id)) ? + msix_name_ct[i] : msix_name_cb[i])); error = request_irq(bfad->msix_tab[i].msix.vector, (irq_handler_t) bfad_msix, 0, @@ -1241,9 +1248,6 @@ bfad_install_msix_handler(struct bfad_s *bfad) free_irq(bfad->msix_tab[j].msix.vector, &bfad->msix_tab[j]); - bfad->bfad_flags &= ~BFAD_MSIX_ON; - pci_disable_msix(bfad->pcidev); - return 1; } } @@ -1261,7 +1265,6 @@ bfad_setup_intr(struct bfad_s *bfad) u32 mask = 0, i, num_bit = 0, max_bit = 0; struct msix_entry msix_entries[MAX_MSIX_ENTRY]; struct pci_dev *pdev = bfad->pcidev; - u16 reg; /* Call BFA to get the msix map for this PCI function. */ bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit); @@ -1269,8 +1272,8 @@ bfad_setup_intr(struct bfad_s *bfad) /* Set up the msix entry table */ bfad_init_msix_entry(bfad, msix_entries, mask, max_bit); - if ((bfa_asic_id_ctc(pdev->device) && !msix_disable_ct) || - (bfa_asic_id_cb(pdev->device) && !msix_disable_cb)) { + if ((bfa_asic_id_ct(pdev->device) && !msix_disable_ct) || + (!bfa_asic_id_ct(pdev->device) && !msix_disable_cb)) { error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec); if (error) { @@ -1291,13 +1294,6 @@ bfad_setup_intr(struct bfad_s *bfad) goto line_based; } - /* Disable INTX in MSI-X mode */ - pci_read_config_word(pdev, PCI_COMMAND, ®); - - if (!(reg & PCI_COMMAND_INTX_DISABLE)) - pci_write_config_word(pdev, PCI_COMMAND, - reg | PCI_COMMAND_INTX_DISABLE); - /* Save the vectors */ for (i = 0; i < bfad->nvec; i++) { bfa_trc(bfad, msix_entries[i].vector); @@ -1319,7 +1315,6 @@ bfad_setup_intr(struct bfad_s *bfad) /* Enable interrupt handler failed */ return 1; } - bfad->bfad_flags |= BFAD_INTX_ON; return error; } @@ -1336,7 +1331,7 @@ bfad_remove_intr(struct bfad_s *bfad) pci_disable_msix(bfad->pcidev); bfad->bfad_flags &= ~BFAD_MSIX_ON; - } else if (bfad->bfad_flags & BFAD_INTX_ON) { + } else { free_irq(bfad->pcidev->irq, bfad); } } @@ -1506,14 +1501,6 @@ struct pci_device_id bfad_id_table[] = { .class = (PCI_CLASS_SERIAL_FIBER << 8), .class_mask = ~0, }, - { - .vendor = BFA_PCI_VENDOR_ID_BROCADE, - .device = BFA_PCI_DEVICE_ID_CT2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = (PCI_CLASS_SERIAL_FIBER << 8), - .class_mask = ~0, - }, {0, 0}, }; @@ -1607,33 +1594,33 @@ bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, static u32 * bfad_load_fwimg(struct pci_dev *pdev) { - if (pdev->device == BFA_PCI_DEVICE_ID_CT2) { - if (bfi_image_ct2_size == 0) - bfad_read_firmware(pdev, &bfi_image_ct2, - &bfi_image_ct2_size, BFAD_FW_FILE_CT2); - return bfi_image_ct2; - } else if (bfa_asic_id_ct(pdev->device)) { - if (bfi_image_ct_size == 0) - bfad_read_firmware(pdev, &bfi_image_ct, - &bfi_image_ct_size, BFAD_FW_FILE_CT); - return bfi_image_ct; + if (pdev->device == BFA_PCI_DEVICE_ID_CT_FC) { + if (bfi_image_ct_fc_size == 0) + bfad_read_firmware(pdev, &bfi_image_ct_fc, + &bfi_image_ct_fc_size, BFAD_FW_FILE_CT_FC); + return bfi_image_ct_fc; + } else if (pdev->device == BFA_PCI_DEVICE_ID_CT) { + if (bfi_image_ct_cna_size == 0) + bfad_read_firmware(pdev, &bfi_image_ct_cna, + &bfi_image_ct_cna_size, BFAD_FW_FILE_CT_CNA); + return bfi_image_ct_cna; } else { - if (bfi_image_cb_size == 0) - bfad_read_firmware(pdev, &bfi_image_cb, - &bfi_image_cb_size, BFAD_FW_FILE_CB); - return bfi_image_cb; + if (bfi_image_cb_fc_size == 0) + bfad_read_firmware(pdev, &bfi_image_cb_fc, + &bfi_image_cb_fc_size, BFAD_FW_FILE_CB_FC); + return bfi_image_cb_fc; } } static void bfad_free_fwimg(void) { - if (bfi_image_ct2_size && bfi_image_ct2) - vfree(bfi_image_ct2); - if (bfi_image_ct_size && bfi_image_ct) - vfree(bfi_image_ct); - if (bfi_image_cb_size && bfi_image_cb) - vfree(bfi_image_cb); + if (bfi_image_ct_fc_size && bfi_image_ct_fc) + vfree(bfi_image_ct_fc); + if (bfi_image_ct_cna_size && bfi_image_ct_cna) + vfree(bfi_image_ct_cna); + if (bfi_image_cb_fc_size && bfi_image_cb_fc) + vfree(bfi_image_cb_fc); } module_init(bfad_init); diff --git a/trunk/drivers/scsi/bfa/bfad_attr.c b/trunk/drivers/scsi/bfa/bfad_attr.c index 9d95844ab463..a94ea4235433 100644 --- a/trunk/drivers/scsi/bfa/bfad_attr.c +++ b/trunk/drivers/scsi/bfa/bfad_attr.c @@ -218,9 +218,6 @@ bfad_im_get_host_speed(struct Scsi_Host *shost) case BFA_PORT_SPEED_10GBPS: fc_host_speed(shost) = FC_PORTSPEED_10GBIT; break; - case BFA_PORT_SPEED_16GBPS: - fc_host_speed(shost) = FC_PORTSPEED_16GBIT; - break; case BFA_PORT_SPEED_8GBPS: fc_host_speed(shost) = FC_PORTSPEED_8GBIT; break; @@ -583,8 +580,6 @@ struct fc_function_template bfad_im_fc_function_template = { .vport_create = bfad_im_vport_create, .vport_delete = bfad_im_vport_delete, .vport_disable = bfad_im_vport_disable, - .bsg_request = bfad_im_bsg_request, - .bsg_timeout = bfad_im_bsg_timeout, }; struct fc_function_template bfad_im_vport_fc_function_template = { @@ -679,10 +674,8 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, struct bfad_s *bfad = im_port->bfad; char model[BFA_ADAPTER_MODEL_NAME_LEN]; char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN]; - int nports = 0; bfa_get_adapter_model(&bfad->bfa, model); - nports = bfa_get_nports(&bfad->bfa); if (!strcmp(model, "Brocade-425")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Brocade 4Gbps PCIe dual port FC HBA"); @@ -691,10 +684,10 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, "Brocade 8Gbps PCIe dual port FC HBA"); else if (!strcmp(model, "Brocade-42B")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 4Gbps PCIe dual port FC HBA for HP"); + "HP 4Gbps PCIe dual port FC HBA"); else if (!strcmp(model, "Brocade-82B")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps PCIe dual port FC HBA for HP"); + "HP 8Gbps PCIe dual port FC HBA"); else if (!strcmp(model, "Brocade-1010")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Brocade 10Gbps single port CNA"); @@ -703,7 +696,7 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, "Brocade 10Gbps dual port CNA"); else if (!strcmp(model, "Brocade-1007")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps CNA for IBM Blade Center"); + "Brocade 10Gbps CNA"); else if (!strcmp(model, "Brocade-415")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Brocade 4Gbps PCIe single port FC HBA"); @@ -712,45 +705,17 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, "Brocade 8Gbps PCIe single port FC HBA"); else if (!strcmp(model, "Brocade-41B")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 4Gbps PCIe single port FC HBA for HP"); + "HP 4Gbps PCIe single port FC HBA"); else if (!strcmp(model, "Brocade-81B")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps PCIe single port FC HBA for HP"); + "HP 8Gbps PCIe single port FC HBA"); else if (!strcmp(model, "Brocade-804")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps FC HBA for HP Bladesystem C-class"); - else if (!strcmp(model, "Brocade-902") || - !strcmp(model, "Brocade-1741")) + "HP Bladesystem C-class 8Gbps FC HBA"); + else if (!strcmp(model, "Brocade-902")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps CNA for Dell M-Series Blade Servers"); - else if (strstr(model, "Brocade-1560")) { - if (nports == 1) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe single port FC HBA"); - else - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe dual port FC HBA"); - } else if (strstr(model, "Brocade-1710")) { - if (nports == 1) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps single port CNA"); - else - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps dual port CNA"); - } else if (strstr(model, "Brocade-1860")) { - if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps single port CNA"); - else if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe single port FC HBA"); - else if (nports == 2 && bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps dual port CNA"); - else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe dual port FC HBA"); - } else + "Brocade 10Gbps CNA"); + else snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Invalid Model"); diff --git a/trunk/drivers/scsi/bfa/bfad_bsg.c b/trunk/drivers/scsi/bfa/bfad_bsg.c deleted file mode 100644 index 89f863ed2334..000000000000 --- a/trunk/drivers/scsi/bfa/bfad_bsg.c +++ /dev/null @@ -1,2163 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include -#include "bfad_drv.h" -#include "bfad_im.h" -#include "bfad_bsg.h" - -BFA_TRC_FILE(LDRV, BSG); - -int -bfad_iocmd_ioc_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - /* If IOC is not in disabled state - return */ - if (!bfa_ioc_is_disabled(&bfad->bfa.ioc)) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_IOC_FAILURE; - return rc; - } - - init_completion(&bfad->enable_comp); - bfa_iocfc_enable(&bfad->bfa); - iocmd->status = BFA_STATUS_OK; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->enable_comp); - - return rc; -} - -int -bfad_iocmd_ioc_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (bfad->disable_active) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return EBUSY; - } - - bfad->disable_active = BFA_TRUE; - init_completion(&bfad->disable_comp); - bfa_iocfc_disable(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - wait_for_completion(&bfad->disable_comp); - bfad->disable_active = BFA_FALSE; - iocmd->status = BFA_STATUS_OK; - - return rc; -} - -static int -bfad_iocmd_ioc_get_info(struct bfad_s *bfad, void *cmd) -{ - int i; - struct bfa_bsg_ioc_info_s *iocmd = (struct bfa_bsg_ioc_info_s *)cmd; - struct bfad_im_port_s *im_port; - struct bfa_port_attr_s pattr; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcport_get_attr(&bfad->bfa, &pattr); - iocmd->nwwn = pattr.nwwn; - iocmd->pwwn = pattr.pwwn; - iocmd->ioc_type = bfa_get_type(&bfad->bfa); - iocmd->mac = bfa_get_mac(&bfad->bfa); - iocmd->factory_mac = bfa_get_mfg_mac(&bfad->bfa); - bfa_get_adapter_serial_num(&bfad->bfa, iocmd->serialnum); - iocmd->factorynwwn = pattr.factorynwwn; - iocmd->factorypwwn = pattr.factorypwwn; - im_port = bfad->pport.im_port; - iocmd->host = im_port->shost->host_no; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - strcpy(iocmd->name, bfad->adapter_name); - strcpy(iocmd->port_name, bfad->port_name); - strcpy(iocmd->hwpath, bfad->pci_name); - - /* set adapter hw path */ - strcpy(iocmd->adapter_hwpath, bfad->pci_name); - i = strlen(iocmd->adapter_hwpath) - 1; - while (iocmd->adapter_hwpath[i] != '.') - i--; - iocmd->adapter_hwpath[i] = '\0'; - iocmd->status = BFA_STATUS_OK; - return 0; -} - -static int -bfad_iocmd_ioc_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_ioc_attr_s *iocmd = (struct bfa_bsg_ioc_attr_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_ioc_get_attr(&bfad->bfa.ioc, &iocmd->ioc_attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - /* fill in driver attr info */ - strcpy(iocmd->ioc_attr.driver_attr.driver, BFAD_DRIVER_NAME); - strncpy(iocmd->ioc_attr.driver_attr.driver_ver, - BFAD_DRIVER_VERSION, BFA_VERSION_LEN); - strcpy(iocmd->ioc_attr.driver_attr.fw_ver, - iocmd->ioc_attr.adapter_attr.fw_ver); - strcpy(iocmd->ioc_attr.driver_attr.bios_ver, - iocmd->ioc_attr.adapter_attr.optrom_ver); - - /* copy chip rev info first otherwise it will be overwritten */ - memcpy(bfad->pci_attr.chip_rev, iocmd->ioc_attr.pci_attr.chip_rev, - sizeof(bfad->pci_attr.chip_rev)); - memcpy(&iocmd->ioc_attr.pci_attr, &bfad->pci_attr, - sizeof(struct bfa_ioc_pci_attr_s)); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_ioc_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_ioc_stats_s *iocmd = (struct bfa_bsg_ioc_stats_s *)cmd; - - bfa_ioc_get_stats(&bfad->bfa, &iocmd->ioc_stats); - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_ioc_get_fwstats(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_ioc_fwstats_s *iocmd = - (struct bfa_bsg_ioc_fwstats_s *)cmd; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_ioc_fwstats_s), - sizeof(struct bfa_fw_stats_s)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - goto out; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_ioc_fwstats_s); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ioc_fw_stats_get(&bfad->bfa.ioc, iocmd_bufptr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - goto out; - } -out: - bfa_trc(bfad, 0x6666); - return 0; -} - -int -bfad_iocmd_iocfc_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_iocfc_attr_s *iocmd = (struct bfa_bsg_iocfc_attr_s *)cmd; - - iocmd->status = BFA_STATUS_OK; - bfa_iocfc_get_attr(&bfad->bfa, &iocmd->iocfc_attr); - - return 0; -} - -int -bfad_iocmd_iocfc_set_intr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_iocfc_intr_s *iocmd = (struct bfa_bsg_iocfc_intr_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_iocfc_israttr_set(&bfad->bfa, &iocmd->attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_port_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_port_enable(&bfad->bfa.modules.port, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - return 0; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - return 0; -} - -int -bfad_iocmd_port_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_port_disable(&bfad->bfa.modules.port, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - return 0; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - return 0; -} - -static int -bfad_iocmd_port_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_port_attr_s *iocmd = (struct bfa_bsg_port_attr_s *)cmd; - struct bfa_lport_attr_s port_attr; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcport_get_attr(&bfad->bfa, &iocmd->attr); - bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->attr.topology != BFA_PORT_TOPOLOGY_NONE) - iocmd->attr.pid = port_attr.pid; - else - iocmd->attr.pid = 0; - - iocmd->attr.port_type = port_attr.port_type; - iocmd->attr.loopback = port_attr.loopback; - iocmd->attr.authfail = port_attr.authfail; - strncpy(iocmd->attr.port_symname.symname, - port_attr.port_cfg.sym_name.symname, - sizeof(port_attr.port_cfg.sym_name.symname)); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_port_get_stats(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_port_stats_s *iocmd = (struct bfa_bsg_port_stats_s *)cmd; - struct bfad_hal_comp fcomp; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_port_stats_s), - sizeof(union bfa_port_stats_u)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_port_stats_s); - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_port_get_stats(&bfad->bfa.modules.port, - iocmd_bufptr, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - goto out; - } - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -static int -bfad_iocmd_lport_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_lport_s *fcs_port; - struct bfa_bsg_lport_attr_s *iocmd = (struct bfa_bsg_lport_attr_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcs_lport_get_attr(fcs_port, &iocmd->port_attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_lport_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_lport_s *fcs_port; - struct bfa_bsg_lport_stats_s *iocmd = - (struct bfa_bsg_lport_stats_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcs_lport_get_stats(fcs_port, &iocmd->port_stats); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_lport_get_iostats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_lport_s *fcs_port; - struct bfa_bsg_lport_iostats_s *iocmd = - (struct bfa_bsg_lport_iostats_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcpim_port_iostats(&bfad->bfa, &iocmd->iostats, - fcs_port->lp_tag); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_lport_get_rports(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_lport_get_rports_s *iocmd = - (struct bfa_bsg_lport_get_rports_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - unsigned long flags; - void *iocmd_bufptr; - - if (iocmd->nrports == 0) - return EINVAL; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_lport_get_rports_s), - sizeof(wwn_t) * iocmd->nrports) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + - sizeof(struct bfa_bsg_lport_get_rports_s); - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, 0); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcs_lport_get_rports(fcs_port, (wwn_t *)iocmd_bufptr, - &iocmd->nrports); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_rport_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_attr_s *iocmd = (struct bfa_bsg_rport_attr_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn); - if (fcs_rport == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - bfa_fcs_rport_get_attr(fcs_rport, &iocmd->attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -static int -bfad_iocmd_rport_get_addr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_scsi_addr_s *iocmd = - (struct bfa_bsg_rport_scsi_addr_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *fcs_itnim; - struct bfad_itnim_s *drv_itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (fcs_itnim == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - drv_itnim = fcs_itnim->itnim_drv; - - if (drv_itnim && drv_itnim->im_port) - iocmd->host = drv_itnim->im_port->shost->host_no; - else { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - iocmd->target = drv_itnim->scsi_tgt_id; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->bus = 0; - iocmd->lun = 0; - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_rport_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_stats_s *iocmd = - (struct bfa_bsg_rport_stats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn); - if (fcs_rport == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - memcpy((void *)&iocmd->stats, (void *)&fcs_rport->stats, - sizeof(struct bfa_rport_stats_s)); - memcpy((void *)&iocmd->stats.hal_stats, - (void *)&(bfa_fcs_rport_get_halrport(fcs_rport)->stats), - sizeof(struct bfa_rport_hal_stats_s)); - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -static int -bfad_iocmd_fabric_get_lports(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_fabric_get_lports_s *iocmd = - (struct bfa_bsg_fabric_get_lports_s *)cmd; - bfa_fcs_vf_t *fcs_vf; - uint32_t nports = iocmd->nports; - unsigned long flags; - void *iocmd_bufptr; - - if (nports == 0) { - iocmd->status = BFA_STATUS_EINVAL; - goto out; - } - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_fabric_get_lports_s), - sizeof(wwn_t[iocmd->nports])) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - goto out; - } - - iocmd_bufptr = (char *)iocmd + - sizeof(struct bfa_bsg_fabric_get_lports_s); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vf = bfa_fcs_vf_lookup(&bfad->bfa_fcs, iocmd->vf_id); - if (fcs_vf == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_VFID; - goto out; - } - bfa_fcs_vf_get_ports(fcs_vf, (wwn_t *)iocmd_bufptr, &nports); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->nports = nports; - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_fcpim_get_modstats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcpim_modstats_s *iocmd = - (struct bfa_bsg_fcpim_modstats_s *)cmd; - struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa); - struct list_head *qe, *qen; - struct bfa_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - /* accumulate IO stats from itnim */ - memset((void *)&iocmd->modstats, 0, sizeof(struct bfa_itnim_iostats_s)); - list_for_each_safe(qe, qen, &fcpim->itnim_q) { - itnim = (struct bfa_itnim_s *) qe; - bfa_fcpim_add_stats(&iocmd->modstats, &(itnim->stats)); - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_fcpim_get_del_itn_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcpim_del_itn_stats_s *iocmd = - (struct bfa_bsg_fcpim_del_itn_stats_s *)cmd; - struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa); - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - memcpy((void *)&iocmd->modstats, (void *)&fcpim->del_itn_stats, - sizeof(struct bfa_fcpim_del_itn_stats_s)); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -static int -bfad_iocmd_itnim_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_itnim_attr_s *iocmd = (struct bfa_bsg_itnim_attr_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->lpwwn); - if (!fcs_port) - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - else - iocmd->status = bfa_fcs_itnim_attr_get(fcs_port, - iocmd->rpwwn, &iocmd->attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -static int -bfad_iocmd_itnim_get_iostats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_itnim_iostats_s *iocmd = - (struct bfa_bsg_itnim_iostats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->lpwwn); - if (!fcs_port) { - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - bfa_trc(bfad, 0); - } else { - itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (itnim == NULL) - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - else { - iocmd->status = BFA_STATUS_OK; - memcpy((void *)&iocmd->iostats, (void *) - &(bfa_fcs_itnim_get_halitn(itnim)->stats), - sizeof(struct bfa_itnim_iostats_s)); - } - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -static int -bfad_iocmd_itnim_get_itnstats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_itnim_itnstats_s *iocmd = - (struct bfa_bsg_itnim_itnstats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->lpwwn); - if (!fcs_port) { - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - bfa_trc(bfad, 0); - } else { - itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (itnim == NULL) - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - else { - iocmd->status = BFA_STATUS_OK; - bfa_fcs_itnim_stats_get(fcs_port, iocmd->rpwwn, - &iocmd->itnstats); - } - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_fcport_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcport_enable(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_fcport_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcport_disable(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_ioc_get_pcifn_cfg(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_cfg_s *iocmd = (struct bfa_bsg_pcifn_cfg_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_query(&bfad->bfa.modules.ablk, - &iocmd->pcifn_cfg, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_pcifn_create(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_s *iocmd = (struct bfa_bsg_pcifn_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_pf_create(&bfad->bfa.modules.ablk, - &iocmd->pcifn_id, iocmd->port, - iocmd->pcifn_class, iocmd->bandwidth, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_pcifn_delete(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_s *iocmd = (struct bfa_bsg_pcifn_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_pf_delete(&bfad->bfa.modules.ablk, - iocmd->pcifn_id, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_pcifn_bw(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_s *iocmd = (struct bfa_bsg_pcifn_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_pf_update(&bfad->bfa.modules.ablk, - iocmd->pcifn_id, iocmd->bandwidth, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - bfa_trc(bfad, iocmd->status); -out: - return 0; -} - -int -bfad_iocmd_adapter_cfg_mode(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_adapter_cfg_mode_s *iocmd = - (struct bfa_bsg_adapter_cfg_mode_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags = 0; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_adapter_config(&bfad->bfa.modules.ablk, - iocmd->cfg.mode, iocmd->cfg.max_pf, - iocmd->cfg.max_vf, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_port_cfg_mode(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_port_cfg_mode_s *iocmd = - (struct bfa_bsg_port_cfg_mode_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags = 0; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_port_config(&bfad->bfa.modules.ablk, - iocmd->instance, iocmd->cfg.mode, - iocmd->cfg.max_pf, iocmd->cfg.max_vf, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_ablk_optrom(struct bfad_s *bfad, unsigned int cmd, void *pcmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (cmd == IOCMD_FLASH_ENABLE_OPTROM) - iocmd->status = bfa_ablk_optrom_en(&bfad->bfa.modules.ablk, - bfad_hcb_comp, &fcomp); - else - iocmd->status = bfa_ablk_optrom_dis(&bfad->bfa.modules.ablk, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_faa_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - struct bfad_hal_comp fcomp; - - init_completion(&fcomp.comp); - iocmd->status = BFA_STATUS_OK; - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_faa_enable(&bfad->bfa, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_faa_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - struct bfad_hal_comp fcomp; - - init_completion(&fcomp.comp); - iocmd->status = BFA_STATUS_OK; - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_faa_disable(&bfad->bfa, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_faa_query(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_faa_attr_s *iocmd = (struct bfa_bsg_faa_attr_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - iocmd->status = BFA_STATUS_OK; - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_faa_query(&bfad->bfa, &iocmd->faa_attr, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_cee_attr(struct bfad_s *bfad, void *cmd, unsigned int payload_len) -{ - struct bfa_bsg_cee_attr_s *iocmd = - (struct bfa_bsg_cee_attr_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp cee_comp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_cee_attr_s), - sizeof(struct bfa_cee_attr_s)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_cee_attr_s); - - cee_comp.status = 0; - init_completion(&cee_comp.comp); - mutex_lock(&bfad_mutex); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_cee_get_attr(&bfad->bfa.modules.cee, iocmd_bufptr, - bfad_hcb_comp, &cee_comp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - mutex_unlock(&bfad_mutex); - bfa_trc(bfad, 0x5555); - goto out; - } - wait_for_completion(&cee_comp.comp); - mutex_unlock(&bfad_mutex); -out: - return 0; -} - -int -bfad_iocmd_cee_get_stats(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_cee_stats_s *iocmd = - (struct bfa_bsg_cee_stats_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp cee_comp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_cee_stats_s), - sizeof(struct bfa_cee_stats_s)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_cee_stats_s); - - cee_comp.status = 0; - init_completion(&cee_comp.comp); - mutex_lock(&bfad_mutex); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_cee_get_stats(&bfad->bfa.modules.cee, iocmd_bufptr, - bfad_hcb_comp, &cee_comp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - mutex_unlock(&bfad_mutex); - bfa_trc(bfad, 0x5555); - goto out; - } - wait_for_completion(&cee_comp.comp); - mutex_unlock(&bfad_mutex); -out: - return 0; -} - -int -bfad_iocmd_cee_reset_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_cee_reset_stats(&bfad->bfa.modules.cee, NULL, NULL); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - bfa_trc(bfad, 0x5555); - return 0; -} - -int -bfad_iocmd_sfp_media(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_sfp_media_s *iocmd = (struct bfa_bsg_sfp_media_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_sfp_media(BFA_SFP_MOD(&bfad->bfa), &iocmd->media, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_SFP_NOT_READY) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_sfp_speed(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_sfp_speed_s *iocmd = (struct bfa_bsg_sfp_speed_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_sfp_speed(BFA_SFP_MOD(&bfad->bfa), iocmd->speed, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_SFP_NOT_READY) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_flash_attr_s *iocmd = - (struct bfa_bsg_flash_attr_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_get_attr(BFA_FLASH(&bfad->bfa), &iocmd->attr, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_erase_part(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_flash_s *iocmd = (struct bfa_bsg_flash_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_erase_part(BFA_FLASH(&bfad->bfa), iocmd->type, - iocmd->instance, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_update_part(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_flash_s *iocmd = (struct bfa_bsg_flash_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp fcomp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_flash_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_flash_s); - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_update_part(BFA_FLASH(&bfad->bfa), - iocmd->type, iocmd->instance, iocmd_bufptr, - iocmd->bufsz, 0, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_read_part(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_flash_s *iocmd = (struct bfa_bsg_flash_s *)cmd; - struct bfad_hal_comp fcomp; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_flash_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_flash_s); - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_read_part(BFA_FLASH(&bfad->bfa), iocmd->type, - iocmd->instance, iocmd_bufptr, iocmd->bufsz, 0, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_temp(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_get_temp_s *iocmd = - (struct bfa_bsg_diag_get_temp_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_tsensor_query(BFA_DIAG_MOD(&bfad->bfa), - &iocmd->result, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_memtest(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_memtest_s *iocmd = - (struct bfa_bsg_diag_memtest_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_memtest(BFA_DIAG_MOD(&bfad->bfa), - &iocmd->memtest, iocmd->pat, - &iocmd->result, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_loopback(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_loopback_s *iocmd = - (struct bfa_bsg_diag_loopback_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcdiag_loopback(&bfad->bfa, iocmd->opmode, - iocmd->speed, iocmd->lpcnt, iocmd->pat, - &iocmd->result, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_fwping(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_fwping_s *iocmd = - (struct bfa_bsg_diag_fwping_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_fwping(BFA_DIAG_MOD(&bfad->bfa), iocmd->cnt, - iocmd->pattern, &iocmd->result, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - bfa_trc(bfad, 0x77771); - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_queuetest(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_qtest_s *iocmd = (struct bfa_bsg_diag_qtest_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcdiag_queuetest(&bfad->bfa, iocmd->force, - iocmd->queue, &iocmd->result, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_sfp(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_sfp_show_s *iocmd = - (struct bfa_bsg_sfp_show_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_sfp_show(BFA_SFP_MOD(&bfad->bfa), &iocmd->sfp, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - bfa_trc(bfad, iocmd->status); -out: - return 0; -} - -int -bfad_iocmd_diag_led(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_led_s *iocmd = (struct bfa_bsg_diag_led_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_ledtest(BFA_DIAG_MOD(&bfad->bfa), - &iocmd->ledtest); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_diag_beacon_lport(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_beacon_s *iocmd = - (struct bfa_bsg_diag_beacon_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_beacon_port(BFA_DIAG_MOD(&bfad->bfa), - iocmd->beacon, iocmd->link_e2e_beacon, - iocmd->second); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_diag_lb_stat(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_lb_stat_s *iocmd = - (struct bfa_bsg_diag_lb_stat_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcdiag_lb_is_running(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - - return 0; -} - -int -bfad_iocmd_phy_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_phy_attr_s *iocmd = - (struct bfa_bsg_phy_attr_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_get_attr(BFA_PHY(&bfad->bfa), iocmd->instance, - &iocmd->attr, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_phy_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_phy_stats_s *iocmd = - (struct bfa_bsg_phy_stats_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_get_stats(BFA_PHY(&bfad->bfa), iocmd->instance, - &iocmd->stats, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_phy_read(struct bfad_s *bfad, void *cmd, unsigned int payload_len) -{ - struct bfa_bsg_phy_s *iocmd = (struct bfa_bsg_phy_s *)cmd; - struct bfad_hal_comp fcomp; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_phy_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_phy_s); - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_read(BFA_PHY(&bfad->bfa), - iocmd->instance, iocmd_bufptr, iocmd->bufsz, - 0, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - if (iocmd->status != BFA_STATUS_OK) - goto out; -out: - return 0; -} - -int -bfad_iocmd_vhba_query(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_vhba_attr_s *iocmd = - (struct bfa_bsg_vhba_attr_s *)cmd; - struct bfa_vhba_attr_s *attr = &iocmd->attr; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - attr->pwwn = bfad->bfa.ioc.attr->pwwn; - attr->nwwn = bfad->bfa.ioc.attr->nwwn; - attr->plog_enabled = (bfa_boolean_t)bfad->bfa.plog->plog_enabled; - attr->io_profile = bfa_fcpim_get_io_profile(&bfad->bfa); - attr->path_tov = bfa_fcpim_path_tov_get(&bfad->bfa); - iocmd->status = BFA_STATUS_OK; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_phy_update(struct bfad_s *bfad, void *cmd, unsigned int payload_len) -{ - struct bfa_bsg_phy_s *iocmd = (struct bfa_bsg_phy_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp fcomp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_phy_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_phy_s); - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_update(BFA_PHY(&bfad->bfa), - iocmd->instance, iocmd_bufptr, iocmd->bufsz, - 0, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_porglog_get(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_debug_s *iocmd = (struct bfa_bsg_debug_s *)cmd; - void *iocmd_bufptr; - - if (iocmd->bufsz < sizeof(struct bfa_plog_s)) { - bfa_trc(bfad, sizeof(struct bfa_plog_s)); - iocmd->status = BFA_STATUS_EINVAL; - goto out; - } - - iocmd->status = BFA_STATUS_OK; - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_debug_s); - memcpy(iocmd_bufptr, (u8 *) &bfad->plog_buf, sizeof(struct bfa_plog_s)); -out: - return 0; -} - -static int -bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd, - unsigned int payload_len) -{ - int rc = EINVAL; - - switch (cmd) { - case IOCMD_IOC_ENABLE: - rc = bfad_iocmd_ioc_enable(bfad, iocmd); - break; - case IOCMD_IOC_DISABLE: - rc = bfad_iocmd_ioc_disable(bfad, iocmd); - break; - case IOCMD_IOC_GET_INFO: - rc = bfad_iocmd_ioc_get_info(bfad, iocmd); - break; - case IOCMD_IOC_GET_ATTR: - rc = bfad_iocmd_ioc_get_attr(bfad, iocmd); - break; - case IOCMD_IOC_GET_STATS: - rc = bfad_iocmd_ioc_get_stats(bfad, iocmd); - break; - case IOCMD_IOC_GET_FWSTATS: - rc = bfad_iocmd_ioc_get_fwstats(bfad, iocmd, payload_len); - break; - case IOCMD_IOCFC_GET_ATTR: - rc = bfad_iocmd_iocfc_get_attr(bfad, iocmd); - break; - case IOCMD_IOCFC_SET_INTR: - rc = bfad_iocmd_iocfc_set_intr(bfad, iocmd); - break; - case IOCMD_PORT_ENABLE: - rc = bfad_iocmd_port_enable(bfad, iocmd); - break; - case IOCMD_PORT_DISABLE: - rc = bfad_iocmd_port_disable(bfad, iocmd); - break; - case IOCMD_PORT_GET_ATTR: - rc = bfad_iocmd_port_get_attr(bfad, iocmd); - break; - case IOCMD_PORT_GET_STATS: - rc = bfad_iocmd_port_get_stats(bfad, iocmd, payload_len); - break; - case IOCMD_LPORT_GET_ATTR: - rc = bfad_iocmd_lport_get_attr(bfad, iocmd); - break; - case IOCMD_LPORT_GET_STATS: - rc = bfad_iocmd_lport_get_stats(bfad, iocmd); - break; - case IOCMD_LPORT_GET_IOSTATS: - rc = bfad_iocmd_lport_get_iostats(bfad, iocmd); - break; - case IOCMD_LPORT_GET_RPORTS: - rc = bfad_iocmd_lport_get_rports(bfad, iocmd, payload_len); - break; - case IOCMD_RPORT_GET_ATTR: - rc = bfad_iocmd_rport_get_attr(bfad, iocmd); - break; - case IOCMD_RPORT_GET_ADDR: - rc = bfad_iocmd_rport_get_addr(bfad, iocmd); - break; - case IOCMD_RPORT_GET_STATS: - rc = bfad_iocmd_rport_get_stats(bfad, iocmd); - break; - case IOCMD_FABRIC_GET_LPORTS: - rc = bfad_iocmd_fabric_get_lports(bfad, iocmd, payload_len); - break; - case IOCMD_FCPIM_MODSTATS: - rc = bfad_iocmd_fcpim_get_modstats(bfad, iocmd); - break; - case IOCMD_FCPIM_DEL_ITN_STATS: - rc = bfad_iocmd_fcpim_get_del_itn_stats(bfad, iocmd); - break; - case IOCMD_ITNIM_GET_ATTR: - rc = bfad_iocmd_itnim_get_attr(bfad, iocmd); - break; - case IOCMD_ITNIM_GET_IOSTATS: - rc = bfad_iocmd_itnim_get_iostats(bfad, iocmd); - break; - case IOCMD_ITNIM_GET_ITNSTATS: - rc = bfad_iocmd_itnim_get_itnstats(bfad, iocmd); - break; - case IOCMD_FCPORT_ENABLE: - rc = bfad_iocmd_fcport_enable(bfad, iocmd); - break; - case IOCMD_FCPORT_DISABLE: - rc = bfad_iocmd_fcport_disable(bfad, iocmd); - break; - case IOCMD_IOC_PCIFN_CFG: - rc = bfad_iocmd_ioc_get_pcifn_cfg(bfad, iocmd); - break; - case IOCMD_PCIFN_CREATE: - rc = bfad_iocmd_pcifn_create(bfad, iocmd); - break; - case IOCMD_PCIFN_DELETE: - rc = bfad_iocmd_pcifn_delete(bfad, iocmd); - break; - case IOCMD_PCIFN_BW: - rc = bfad_iocmd_pcifn_bw(bfad, iocmd); - break; - case IOCMD_ADAPTER_CFG_MODE: - rc = bfad_iocmd_adapter_cfg_mode(bfad, iocmd); - break; - case IOCMD_PORT_CFG_MODE: - rc = bfad_iocmd_port_cfg_mode(bfad, iocmd); - break; - case IOCMD_FLASH_ENABLE_OPTROM: - case IOCMD_FLASH_DISABLE_OPTROM: - rc = bfad_iocmd_ablk_optrom(bfad, cmd, iocmd); - break; - case IOCMD_FAA_ENABLE: - rc = bfad_iocmd_faa_enable(bfad, iocmd); - break; - case IOCMD_FAA_DISABLE: - rc = bfad_iocmd_faa_disable(bfad, iocmd); - break; - case IOCMD_FAA_QUERY: - rc = bfad_iocmd_faa_query(bfad, iocmd); - break; - case IOCMD_CEE_GET_ATTR: - rc = bfad_iocmd_cee_attr(bfad, iocmd, payload_len); - break; - case IOCMD_CEE_GET_STATS: - rc = bfad_iocmd_cee_get_stats(bfad, iocmd, payload_len); - break; - case IOCMD_CEE_RESET_STATS: - rc = bfad_iocmd_cee_reset_stats(bfad, iocmd); - break; - case IOCMD_SFP_MEDIA: - rc = bfad_iocmd_sfp_media(bfad, iocmd); - break; - case IOCMD_SFP_SPEED: - rc = bfad_iocmd_sfp_speed(bfad, iocmd); - break; - case IOCMD_FLASH_GET_ATTR: - rc = bfad_iocmd_flash_get_attr(bfad, iocmd); - break; - case IOCMD_FLASH_ERASE_PART: - rc = bfad_iocmd_flash_erase_part(bfad, iocmd); - break; - case IOCMD_FLASH_UPDATE_PART: - rc = bfad_iocmd_flash_update_part(bfad, iocmd, payload_len); - break; - case IOCMD_FLASH_READ_PART: - rc = bfad_iocmd_flash_read_part(bfad, iocmd, payload_len); - break; - case IOCMD_DIAG_TEMP: - rc = bfad_iocmd_diag_temp(bfad, iocmd); - break; - case IOCMD_DIAG_MEMTEST: - rc = bfad_iocmd_diag_memtest(bfad, iocmd); - break; - case IOCMD_DIAG_LOOPBACK: - rc = bfad_iocmd_diag_loopback(bfad, iocmd); - break; - case IOCMD_DIAG_FWPING: - rc = bfad_iocmd_diag_fwping(bfad, iocmd); - break; - case IOCMD_DIAG_QUEUETEST: - rc = bfad_iocmd_diag_queuetest(bfad, iocmd); - break; - case IOCMD_DIAG_SFP: - rc = bfad_iocmd_diag_sfp(bfad, iocmd); - break; - case IOCMD_DIAG_LED: - rc = bfad_iocmd_diag_led(bfad, iocmd); - break; - case IOCMD_DIAG_BEACON_LPORT: - rc = bfad_iocmd_diag_beacon_lport(bfad, iocmd); - break; - case IOCMD_DIAG_LB_STAT: - rc = bfad_iocmd_diag_lb_stat(bfad, iocmd); - break; - case IOCMD_PHY_GET_ATTR: - rc = bfad_iocmd_phy_get_attr(bfad, iocmd); - break; - case IOCMD_PHY_GET_STATS: - rc = bfad_iocmd_phy_get_stats(bfad, iocmd); - break; - case IOCMD_PHY_UPDATE_FW: - rc = bfad_iocmd_phy_update(bfad, iocmd, payload_len); - break; - case IOCMD_PHY_READ_FW: - rc = bfad_iocmd_phy_read(bfad, iocmd, payload_len); - break; - case IOCMD_VHBA_QUERY: - rc = bfad_iocmd_vhba_query(bfad, iocmd); - break; - case IOCMD_DEBUG_PORTLOG: - rc = bfad_iocmd_porglog_get(bfad, iocmd); - break; - default: - rc = EINVAL; - break; - } - return -rc; -} - -static int -bfad_im_bsg_vendor_request(struct fc_bsg_job *job) -{ - uint32_t vendor_cmd = job->request->rqst_data.h_vendor.vendor_cmd[0]; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) job->shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - void *payload_kbuf; - int rc = -EINVAL; - - /* Allocate a temp buffer to hold the passed in user space command */ - payload_kbuf = kzalloc(job->request_payload.payload_len, GFP_KERNEL); - if (!payload_kbuf) { - rc = -ENOMEM; - goto out; - } - - /* Copy the sg_list passed in to a linear buffer: holds the cmnd data */ - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, payload_kbuf, - job->request_payload.payload_len); - - /* Invoke IOCMD handler - to handle all the vendor command requests */ - rc = bfad_iocmd_handler(bfad, vendor_cmd, payload_kbuf, - job->request_payload.payload_len); - if (rc != BFA_STATUS_OK) - goto error; - - /* Copy the response data to the job->reply_payload sg_list */ - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - payload_kbuf, - job->reply_payload.payload_len); - - /* free the command buffer */ - kfree(payload_kbuf); - - /* Fill the BSG job reply data */ - job->reply_len = job->reply_payload.payload_len; - job->reply->reply_payload_rcv_len = job->reply_payload.payload_len; - job->reply->result = rc; - - job->job_done(job); - return rc; -error: - /* free the command buffer */ - kfree(payload_kbuf); -out: - job->reply->result = rc; - job->reply_len = sizeof(uint32_t); - job->reply->reply_payload_rcv_len = 0; - return rc; -} - -/* FC passthru call backs */ -u64 -bfad_fcxp_get_req_sgaddr_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - u64 addr; - - sge = drv_fcxp->req_sge + sgeid; - addr = (u64)(size_t) sge->sg_addr; - return addr; -} - -u32 -bfad_fcxp_get_req_sglen_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - - sge = drv_fcxp->req_sge + sgeid; - return sge->sg_len; -} - -u64 -bfad_fcxp_get_rsp_sgaddr_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - u64 addr; - - sge = drv_fcxp->rsp_sge + sgeid; - addr = (u64)(size_t) sge->sg_addr; - return addr; -} - -u32 -bfad_fcxp_get_rsp_sglen_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - - sge = drv_fcxp->rsp_sge + sgeid; - return sge->sg_len; -} - -void -bfad_send_fcpt_cb(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - - drv_fcxp->req_status = req_status; - drv_fcxp->rsp_len = rsp_len; - - /* bfa_fcxp will be automatically freed by BFA */ - drv_fcxp->bfa_fcxp = NULL; - complete(&drv_fcxp->comp); -} - -struct bfad_buf_info * -bfad_fcxp_map_sg(struct bfad_s *bfad, void *payload_kbuf, - uint32_t payload_len, uint32_t *num_sgles) -{ - struct bfad_buf_info *buf_base, *buf_info; - struct bfa_sge_s *sg_table; - int sge_num = 1; - - buf_base = kzalloc((sizeof(struct bfad_buf_info) + - sizeof(struct bfa_sge_s)) * sge_num, GFP_KERNEL); - if (!buf_base) - return NULL; - - sg_table = (struct bfa_sge_s *) (((uint8_t *)buf_base) + - (sizeof(struct bfad_buf_info) * sge_num)); - - /* Allocate dma coherent memory */ - buf_info = buf_base; - buf_info->size = payload_len; - buf_info->virt = dma_alloc_coherent(&bfad->pcidev->dev, buf_info->size, - &buf_info->phys, GFP_KERNEL); - if (!buf_info->virt) - goto out_free_mem; - - /* copy the linear bsg buffer to buf_info */ - memset(buf_info->virt, 0, buf_info->size); - memcpy(buf_info->virt, payload_kbuf, buf_info->size); - - /* - * Setup SG table - */ - sg_table->sg_len = buf_info->size; - sg_table->sg_addr = (void *)(size_t) buf_info->phys; - - *num_sgles = sge_num; - - return buf_base; - -out_free_mem: - kfree(buf_base); - return NULL; -} - -void -bfad_fcxp_free_mem(struct bfad_s *bfad, struct bfad_buf_info *buf_base, - uint32_t num_sgles) -{ - int i; - struct bfad_buf_info *buf_info = buf_base; - - if (buf_base) { - for (i = 0; i < num_sgles; buf_info++, i++) { - if (buf_info->virt != NULL) - dma_free_coherent(&bfad->pcidev->dev, - buf_info->size, buf_info->virt, - buf_info->phys); - } - kfree(buf_base); - } -} - -int -bfad_fcxp_bsg_send(struct fc_bsg_job *job, struct bfad_fcxp *drv_fcxp, - bfa_bsg_fcpt_t *bsg_fcpt) -{ - struct bfa_fcxp_s *hal_fcxp; - struct bfad_s *bfad = drv_fcxp->port->bfad; - unsigned long flags; - uint8_t lp_tag; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - - /* Allocate bfa_fcxp structure */ - hal_fcxp = bfa_fcxp_alloc(drv_fcxp, &bfad->bfa, - drv_fcxp->num_req_sgles, - drv_fcxp->num_rsp_sgles, - bfad_fcxp_get_req_sgaddr_cb, - bfad_fcxp_get_req_sglen_cb, - bfad_fcxp_get_rsp_sgaddr_cb, - bfad_fcxp_get_rsp_sglen_cb); - if (!hal_fcxp) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return BFA_STATUS_ENOMEM; - } - - drv_fcxp->bfa_fcxp = hal_fcxp; - - lp_tag = bfa_lps_get_tag_from_pid(&bfad->bfa, bsg_fcpt->fchs.s_id); - - bfa_fcxp_send(hal_fcxp, drv_fcxp->bfa_rport, bsg_fcpt->vf_id, lp_tag, - bsg_fcpt->cts, bsg_fcpt->cos, - job->request_payload.payload_len, - &bsg_fcpt->fchs, bfad_send_fcpt_cb, bfad, - job->reply_payload.payload_len, bsg_fcpt->tsecs); - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return BFA_STATUS_OK; -} - -int -bfad_im_bsg_els_ct_request(struct fc_bsg_job *job) -{ - struct bfa_bsg_data *bsg_data; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) job->shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - bfa_bsg_fcpt_t *bsg_fcpt; - struct bfad_fcxp *drv_fcxp; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - uint32_t command_type = job->request->msgcode; - unsigned long flags; - struct bfad_buf_info *rsp_buf_info; - void *req_kbuf = NULL, *rsp_kbuf = NULL; - int rc = -EINVAL; - - job->reply_len = sizeof(uint32_t); /* Atleast uint32_t reply_len */ - job->reply->reply_payload_rcv_len = 0; - - /* Get the payload passed in from userspace */ - bsg_data = (struct bfa_bsg_data *) (((char *)job->request) + - sizeof(struct fc_bsg_request)); - if (bsg_data == NULL) - goto out; - - /* - * Allocate buffer for bsg_fcpt and do a copy_from_user op for payload - * buffer of size bsg_data->payload_len - */ - bsg_fcpt = (struct bfa_bsg_fcpt_s *) - kzalloc(bsg_data->payload_len, GFP_KERNEL); - if (!bsg_fcpt) - goto out; - - if (copy_from_user((uint8_t *)bsg_fcpt, bsg_data->payload, - bsg_data->payload_len)) { - kfree(bsg_fcpt); - goto out; - } - - drv_fcxp = kzalloc(sizeof(struct bfad_fcxp), GFP_KERNEL); - if (drv_fcxp == NULL) { - rc = -ENOMEM; - goto out; - } - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, bsg_fcpt->vf_id, - bsg_fcpt->lpwwn); - if (fcs_port == NULL) { - bsg_fcpt->status = BFA_STATUS_UNKNOWN_LWWN; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - /* Check if the port is online before sending FC Passthru cmd */ - if (!bfa_fcs_lport_is_online(fcs_port)) { - bsg_fcpt->status = BFA_STATUS_PORT_OFFLINE; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - drv_fcxp->port = fcs_port->bfad_port; - - if (drv_fcxp->port->bfad == 0) - drv_fcxp->port->bfad = bfad; - - /* Fetch the bfa_rport - if nexus needed */ - if (command_type == FC_BSG_HST_ELS_NOLOGIN || - command_type == FC_BSG_HST_CT) { - /* BSG HST commands: no nexus needed */ - drv_fcxp->bfa_rport = NULL; - - } else if (command_type == FC_BSG_RPT_ELS || - command_type == FC_BSG_RPT_CT) { - /* BSG RPT commands: nexus needed */ - fcs_rport = bfa_fcs_lport_get_rport_by_pwwn(fcs_port, - bsg_fcpt->dpwwn); - if (fcs_rport == NULL) { - bsg_fcpt->status = BFA_STATUS_UNKNOWN_RWWN; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - drv_fcxp->bfa_rport = fcs_rport->bfa_rport; - - } else { /* Unknown BSG msgcode; return -EINVAL */ - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - /* allocate memory for req / rsp buffers */ - req_kbuf = kzalloc(job->request_payload.payload_len, GFP_KERNEL); - if (!req_kbuf) { - printk(KERN_INFO "bfa %s: fcpt request buffer alloc failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - rsp_kbuf = kzalloc(job->reply_payload.payload_len, GFP_KERNEL); - if (!rsp_kbuf) { - printk(KERN_INFO "bfa %s: fcpt response buffer alloc failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - /* map req sg - copy the sg_list passed in to the linear buffer */ - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, req_kbuf, - job->request_payload.payload_len); - - drv_fcxp->reqbuf_info = bfad_fcxp_map_sg(bfad, req_kbuf, - job->request_payload.payload_len, - &drv_fcxp->num_req_sgles); - if (!drv_fcxp->reqbuf_info) { - printk(KERN_INFO "bfa %s: fcpt request fcxp_map_sg failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - drv_fcxp->req_sge = (struct bfa_sge_s *) - (((uint8_t *)drv_fcxp->reqbuf_info) + - (sizeof(struct bfad_buf_info) * - drv_fcxp->num_req_sgles)); - - /* map rsp sg */ - drv_fcxp->rspbuf_info = bfad_fcxp_map_sg(bfad, rsp_kbuf, - job->reply_payload.payload_len, - &drv_fcxp->num_rsp_sgles); - if (!drv_fcxp->rspbuf_info) { - printk(KERN_INFO "bfa %s: fcpt response fcxp_map_sg failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - rsp_buf_info = (struct bfad_buf_info *)drv_fcxp->rspbuf_info; - drv_fcxp->rsp_sge = (struct bfa_sge_s *) - (((uint8_t *)drv_fcxp->rspbuf_info) + - (sizeof(struct bfad_buf_info) * - drv_fcxp->num_rsp_sgles)); - - /* fcxp send */ - init_completion(&drv_fcxp->comp); - rc = bfad_fcxp_bsg_send(job, drv_fcxp, bsg_fcpt); - if (rc == BFA_STATUS_OK) { - wait_for_completion(&drv_fcxp->comp); - bsg_fcpt->status = drv_fcxp->req_status; - } else { - bsg_fcpt->status = rc; - goto out_free_mem; - } - - /* fill the job->reply data */ - if (drv_fcxp->req_status == BFA_STATUS_OK) { - job->reply_len = drv_fcxp->rsp_len; - job->reply->reply_payload_rcv_len = drv_fcxp->rsp_len; - job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; - } else { - job->reply->reply_payload_rcv_len = - sizeof(struct fc_bsg_ctels_reply); - job->reply_len = sizeof(uint32_t); - job->reply->reply_data.ctels_reply.status = - FC_CTELS_STATUS_REJECT; - } - - /* Copy the response data to the reply_payload sg list */ - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - (uint8_t *)rsp_buf_info->virt, - job->reply_payload.payload_len); - -out_free_mem: - bfad_fcxp_free_mem(bfad, drv_fcxp->rspbuf_info, - drv_fcxp->num_rsp_sgles); - bfad_fcxp_free_mem(bfad, drv_fcxp->reqbuf_info, - drv_fcxp->num_req_sgles); - kfree(req_kbuf); - kfree(rsp_kbuf); - - /* Need a copy to user op */ - if (copy_to_user(bsg_data->payload, (void *) bsg_fcpt, - bsg_data->payload_len)) - rc = -EIO; - - kfree(bsg_fcpt); - kfree(drv_fcxp); -out: - job->reply->result = rc; - - if (rc == BFA_STATUS_OK) - job->job_done(job); - - return rc; -} - -int -bfad_im_bsg_request(struct fc_bsg_job *job) -{ - uint32_t rc = BFA_STATUS_OK; - - switch (job->request->msgcode) { - case FC_BSG_HST_VENDOR: - /* Process BSG HST Vendor requests */ - rc = bfad_im_bsg_vendor_request(job); - break; - case FC_BSG_HST_ELS_NOLOGIN: - case FC_BSG_RPT_ELS: - case FC_BSG_HST_CT: - case FC_BSG_RPT_CT: - /* Process BSG ELS/CT commands */ - rc = bfad_im_bsg_els_ct_request(job); - break; - default: - job->reply->result = rc = -EINVAL; - job->reply->reply_payload_rcv_len = 0; - break; - } - - return rc; -} - -int -bfad_im_bsg_timeout(struct fc_bsg_job *job) -{ - /* Don't complete the BSG job request - return -EAGAIN - * to reset bsg job timeout : for ELS/CT pass thru we - * already have timer to track the request. - */ - return -EAGAIN; -} diff --git a/trunk/drivers/scsi/bfa/bfad_bsg.h b/trunk/drivers/scsi/bfa/bfad_bsg.h deleted file mode 100644 index 99b0e8a70c89..000000000000 --- a/trunk/drivers/scsi/bfa/bfad_bsg.h +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef BFAD_BSG_H -#define BFAD_BSG_H - -#include "bfa_defs.h" -#include "bfa_defs_fcs.h" - -/* Definitions of vendor unique structures and command codes passed in - * using FC_BSG_HST_VENDOR message code. - */ -enum { - IOCMD_IOC_ENABLE = 0x1, - IOCMD_IOC_DISABLE, - IOCMD_IOC_GET_ATTR, - IOCMD_IOC_GET_INFO, - IOCMD_IOC_GET_STATS, - IOCMD_IOC_GET_FWSTATS, - IOCMD_IOCFC_GET_ATTR, - IOCMD_IOCFC_SET_INTR, - IOCMD_PORT_ENABLE, - IOCMD_PORT_DISABLE, - IOCMD_PORT_GET_ATTR, - IOCMD_PORT_GET_STATS, - IOCMD_LPORT_GET_ATTR, - IOCMD_LPORT_GET_RPORTS, - IOCMD_LPORT_GET_STATS, - IOCMD_LPORT_GET_IOSTATS, - IOCMD_RPORT_GET_ATTR, - IOCMD_RPORT_GET_ADDR, - IOCMD_RPORT_GET_STATS, - IOCMD_FABRIC_GET_LPORTS, - IOCMD_FCPIM_MODSTATS, - IOCMD_FCPIM_DEL_ITN_STATS, - IOCMD_ITNIM_GET_ATTR, - IOCMD_ITNIM_GET_IOSTATS, - IOCMD_ITNIM_GET_ITNSTATS, - IOCMD_IOC_PCIFN_CFG, - IOCMD_FCPORT_ENABLE, - IOCMD_FCPORT_DISABLE, - IOCMD_PCIFN_CREATE, - IOCMD_PCIFN_DELETE, - IOCMD_PCIFN_BW, - IOCMD_ADAPTER_CFG_MODE, - IOCMD_PORT_CFG_MODE, - IOCMD_FLASH_ENABLE_OPTROM, - IOCMD_FLASH_DISABLE_OPTROM, - IOCMD_FAA_ENABLE, - IOCMD_FAA_DISABLE, - IOCMD_FAA_QUERY, - IOCMD_CEE_GET_ATTR, - IOCMD_CEE_GET_STATS, - IOCMD_CEE_RESET_STATS, - IOCMD_SFP_MEDIA, - IOCMD_SFP_SPEED, - IOCMD_FLASH_GET_ATTR, - IOCMD_FLASH_ERASE_PART, - IOCMD_FLASH_UPDATE_PART, - IOCMD_FLASH_READ_PART, - IOCMD_DIAG_TEMP, - IOCMD_DIAG_MEMTEST, - IOCMD_DIAG_LOOPBACK, - IOCMD_DIAG_FWPING, - IOCMD_DIAG_QUEUETEST, - IOCMD_DIAG_SFP, - IOCMD_DIAG_LED, - IOCMD_DIAG_BEACON_LPORT, - IOCMD_DIAG_LB_STAT, - IOCMD_PHY_GET_ATTR, - IOCMD_PHY_GET_STATS, - IOCMD_PHY_UPDATE_FW, - IOCMD_PHY_READ_FW, - IOCMD_VHBA_QUERY, - IOCMD_DEBUG_PORTLOG, -}; - -struct bfa_bsg_gen_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; -}; - -struct bfa_bsg_ioc_info_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - char serialnum[64]; - char hwpath[BFA_STRING_32]; - char adapter_hwpath[BFA_STRING_32]; - char guid[BFA_ADAPTER_SYM_NAME_LEN*2]; - char name[BFA_ADAPTER_SYM_NAME_LEN]; - char port_name[BFA_ADAPTER_SYM_NAME_LEN]; - char eth_name[BFA_ADAPTER_SYM_NAME_LEN]; - wwn_t pwwn; - wwn_t nwwn; - wwn_t factorypwwn; - wwn_t factorynwwn; - mac_t mac; - mac_t factory_mac; /* Factory mac address */ - mac_t current_mac; /* Currently assigned mac address */ - enum bfa_ioc_type_e ioc_type; - u16 pvid; /* Port vlan id */ - u16 rsvd1; - u32 host; - u32 bandwidth; /* For PF support */ - u32 rsvd2; -}; - -struct bfa_bsg_ioc_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_ioc_attr_s ioc_attr; -}; - -struct bfa_bsg_ioc_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_ioc_stats_s ioc_stats; -}; - -struct bfa_bsg_ioc_fwstats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_iocfc_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_iocfc_attr_s iocfc_attr; -}; - -struct bfa_bsg_iocfc_intr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_iocfc_intr_attr_s attr; -}; - -struct bfa_bsg_port_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_port_attr_s attr; -}; - -struct bfa_bsg_port_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_lport_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - struct bfa_lport_attr_s port_attr; -}; - -struct bfa_bsg_lport_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - struct bfa_lport_stats_s port_stats; -}; - -struct bfa_bsg_lport_iostats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - struct bfa_itnim_iostats_s iostats; -}; - -struct bfa_bsg_lport_get_rports_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - u64 rbuf_ptr; - u32 nrports; - u32 rsvd; -}; - -struct bfa_bsg_rport_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; - struct bfa_rport_attr_s attr; -}; - -struct bfa_bsg_rport_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; - struct bfa_rport_stats_s stats; -}; - -struct bfa_bsg_rport_scsi_addr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; - u32 host; - u32 bus; - u32 target; - u32 lun; -}; - -struct bfa_bsg_fabric_get_lports_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - u64 buf_ptr; - u32 nports; - u32 rsvd; -}; - -struct bfa_bsg_fcpim_modstats_s { - bfa_status_t status; - u16 bfad_num; - struct bfa_itnim_iostats_s modstats; -}; - -struct bfa_bsg_fcpim_del_itn_stats_s { - bfa_status_t status; - u16 bfad_num; - struct bfa_fcpim_del_itn_stats_s modstats; -}; - -struct bfa_bsg_itnim_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t lpwwn; - wwn_t rpwwn; - struct bfa_itnim_attr_s attr; -}; - -struct bfa_bsg_itnim_iostats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t lpwwn; - wwn_t rpwwn; - struct bfa_itnim_iostats_s iostats; -}; - -struct bfa_bsg_itnim_itnstats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t lpwwn; - wwn_t rpwwn; - struct bfa_itnim_stats_s itnstats; -}; - -struct bfa_bsg_pcifn_cfg_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_ablk_cfg_s pcifn_cfg; -}; - -struct bfa_bsg_pcifn_s { - bfa_status_t status; - u16 bfad_num; - u16 pcifn_id; - u32 bandwidth; - u8 port; - enum bfi_pcifn_class pcifn_class; - u8 rsvd[1]; -}; - -struct bfa_bsg_adapter_cfg_mode_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_adapter_cfg_mode_s cfg; -}; - -struct bfa_bsg_port_cfg_mode_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - struct bfa_port_cfg_mode_s cfg; -}; - -struct bfa_bsg_faa_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_faa_attr_s faa_attr; -}; - -struct bfa_bsg_cee_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_cee_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_sfp_media_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - enum bfa_defs_sfp_media_e media; -}; - -struct bfa_bsg_sfp_speed_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - enum bfa_port_speed speed; -}; - -struct bfa_bsg_flash_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_flash_attr_s attr; -}; - -struct bfa_bsg_flash_s { - bfa_status_t status; - u16 bfad_num; - u8 instance; - u8 rsvd; - enum bfa_flash_part_type type; - int bufsz; - u64 buf_ptr; -}; - -struct bfa_bsg_diag_get_temp_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_diag_results_tempsensor_s result; -}; - -struct bfa_bsg_diag_memtest_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd[3]; - u32 pat; - struct bfa_diag_memtest_result result; - struct bfa_diag_memtest_s memtest; -}; - -struct bfa_bsg_diag_loopback_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - enum bfa_port_opmode opmode; - enum bfa_port_speed speed; - u32 lpcnt; - u32 pat; - struct bfa_diag_loopback_result_s result; -}; - -struct bfa_bsg_diag_fwping_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 cnt; - u32 pattern; - struct bfa_diag_results_fwping result; -}; - -struct bfa_bsg_diag_qtest_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 force; - u32 queue; - struct bfa_diag_qtest_result_s result; -}; - -struct bfa_bsg_sfp_show_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct sfp_mem_s sfp; -}; - -struct bfa_bsg_diag_led_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_diag_ledtest_s ledtest; -}; - -struct bfa_bsg_diag_beacon_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - bfa_boolean_t beacon; - bfa_boolean_t link_e2e_beacon; - u32 second; -}; - -struct bfa_bsg_diag_lb_stat_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; -}; - -struct bfa_bsg_phy_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - struct bfa_phy_attr_s attr; -}; - -struct bfa_bsg_phy_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - u64 bufsz; - u64 buf_ptr; -}; - -struct bfa_bsg_debug_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 bufsz; - int inst_no; - u64 buf_ptr; - u64 offset; -}; - -struct bfa_bsg_phy_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - struct bfa_phy_stats_s stats; -}; - -struct bfa_bsg_vhba_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 pcifn_id; - struct bfa_vhba_attr_s attr; -}; - -struct bfa_bsg_fcpt_s { - bfa_status_t status; - u16 vf_id; - wwn_t lpwwn; - wwn_t dpwwn; - u32 tsecs; - int cts; - enum fc_cos cos; - struct fchs_s fchs; -}; -#define bfa_bsg_fcpt_t struct bfa_bsg_fcpt_s - -struct bfa_bsg_data { - int payload_len; - void *payload; -}; - -#define bfad_chk_iocmd_sz(__payload_len, __hdrsz, __bufsz) \ - (((__payload_len) != ((__hdrsz) + (__bufsz))) ? \ - BFA_STATUS_FAILED : BFA_STATUS_OK) - -#endif /* BFAD_BSG_H */ diff --git a/trunk/drivers/scsi/bfa/bfad_debugfs.c b/trunk/drivers/scsi/bfa/bfad_debugfs.c index b412e0300dd4..48be0c54f2de 100644 --- a/trunk/drivers/scsi/bfa/bfad_debugfs.c +++ b/trunk/drivers/scsi/bfa/bfad_debugfs.c @@ -214,10 +214,10 @@ bfad_debugfs_read(struct file *file, char __user *buf, #define BFA_REG_CT_ADDRSZ (0x40000) #define BFA_REG_CB_ADDRSZ (0x20000) -#define BFA_REG_ADDRSZ(__ioc) \ - ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \ - BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ)) -#define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1) +#define BFA_REG_ADDRSZ(__bfa) \ + ((bfa_ioc_devid(&(__bfa)->ioc) == BFA_PCI_DEVICE_ID_CT) ? \ + BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ) +#define BFA_REG_ADDRMSK(__bfa) ((u32)(BFA_REG_ADDRSZ(__bfa) - 1)) static bfa_status_t bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len) @@ -236,7 +236,7 @@ bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len) return BFA_STATUS_EINVAL; } else { /* CB register space 64KB */ - if ((offset + (len<<2)) > BFA_REG_ADDRMSK(&bfa->ioc)) + if ((offset + (len<<2)) > BFA_REG_ADDRMSK(bfa)) return BFA_STATUS_EINVAL; } return BFA_STATUS_OK; @@ -317,7 +317,7 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf, bfad->reglen = len << 2; rb = bfa_ioc_bar0(ioc); - addr &= BFA_REG_ADDRMSK(ioc); + addr &= BFA_REG_ADDRMSK(bfa); /* offset and len sanity check */ rc = bfad_reg_offset_check(bfa, addr, len); @@ -380,7 +380,7 @@ bfad_debugfs_write_regwr(struct file *file, const char __user *buf, } kfree(kern_buf); - addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */ + addr &= BFA_REG_ADDRMSK(bfa); /* offset only 17 bit and word align */ /* offset and len sanity check */ rc = bfad_reg_offset_check(bfa, addr, 1); diff --git a/trunk/drivers/scsi/bfa/bfad_drv.h b/trunk/drivers/scsi/bfa/bfad_drv.h index 48661a2726d7..7f9ea90254cd 100644 --- a/trunk/drivers/scsi/bfa/bfad_drv.h +++ b/trunk/drivers/scsi/bfa/bfad_drv.h @@ -43,7 +43,6 @@ #include #include #include -#include #include "bfa_modules.h" #include "bfa_fcs.h" @@ -56,7 +55,7 @@ #ifdef BFA_DRIVER_VERSION #define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION #else -#define BFAD_DRIVER_VERSION "3.0.2.1" +#define BFAD_DRIVER_VERSION "2.3.2.3" #endif #define BFAD_PROTO_NAME FCPI_NAME @@ -80,7 +79,7 @@ #define BFAD_HAL_INIT_FAIL 0x00000100 #define BFAD_FC4_PROBE_DONE 0x00000200 #define BFAD_PORT_DELETE 0x00000001 -#define BFAD_INTX_ON 0x00000400 + /* * BFAD related definition */ @@ -93,8 +92,6 @@ */ #define BFAD_LUN_QUEUE_DEPTH 32 #define BFAD_IO_MAX_SGE SG_ALL -#define BFAD_MIN_SECTORS 128 /* 64k */ -#define BFAD_MAX_SECTORS 0xFFFF /* 32 MB */ #define bfad_isr_t irq_handler_t @@ -113,7 +110,6 @@ struct bfad_msix_s { enum { BFA_TRC_LDRV_BFAD = 1, BFA_TRC_LDRV_IM = 2, - BFA_TRC_LDRV_BSG = 3, }; enum bfad_port_pvb_type { @@ -193,10 +189,8 @@ struct bfad_s { struct bfa_pcidev_s hal_pcidev; struct bfa_ioc_pci_attr_s pci_attr; void __iomem *pci_bar0_kva; - void __iomem *pci_bar2_kva; struct completion comp; struct completion suspend; - struct completion enable_comp; struct completion disable_comp; bfa_boolean_t disable_active; struct bfad_port_s pport; /* physical port of the BFAD */ @@ -279,6 +273,21 @@ struct bfad_hal_comp { struct completion comp; }; +/* + * Macro to obtain the immediate lower power + * of two for the integer. + */ +#define nextLowerInt(x) \ +do { \ + int __i; \ + (*x)--; \ + for (__i = 1; __i < (sizeof(int)*8); __i <<= 1) \ + (*x) = (*x) | (*x) >> __i; \ + (*x)++; \ + (*x) = (*x) >> 1; \ +} while (0) + + #define BFA_LOG(level, bfad, mask, fmt, arg...) \ do { \ if (((mask) == 4) || (level[1] <= '4')) \ @@ -345,7 +354,6 @@ extern int msix_disable_ct; extern int fdmi_enable; extern int supported_fc4s; extern int pcie_max_read_reqsz; -extern int max_xfer_size; extern int bfa_debugfs_enable; extern struct mutex bfad_mutex; diff --git a/trunk/drivers/scsi/bfa/bfad_im.c b/trunk/drivers/scsi/bfa/bfad_im.c index f2bf81265ae5..c2b36179e8e8 100644 --- a/trunk/drivers/scsi/bfa/bfad_im.c +++ b/trunk/drivers/scsi/bfa/bfad_im.c @@ -175,11 +175,21 @@ bfad_im_info(struct Scsi_Host *shost) struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; struct bfad_s *bfad = im_port->bfad; + struct bfa_s *bfa = &bfad->bfa; + struct bfa_ioc_s *ioc = &bfa->ioc; + char model[BFA_ADAPTER_MODEL_NAME_LEN]; + + bfa_get_adapter_model(bfa, model); memset(bfa_buf, 0, sizeof(bfa_buf)); - snprintf(bfa_buf, sizeof(bfa_buf), - "Brocade FC/FCOE Adapter, " "hwpath: %s driver: %s", - bfad->pci_name, BFAD_DRIVER_VERSION); + if (ioc->ctdev && !ioc->fcmode) + snprintf(bfa_buf, sizeof(bfa_buf), + "Brocade FCOE Adapter, " "model: %s hwpath: %s driver: %s", + model, bfad->pci_name, BFAD_DRIVER_VERSION); + else + snprintf(bfa_buf, sizeof(bfa_buf), + "Brocade FC Adapter, " "model: %s hwpath: %s driver: %s", + model, bfad->pci_name, BFAD_DRIVER_VERSION); return bfa_buf; } @@ -562,6 +572,9 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, goto out_fc_rel; } + /* setup host fixed attribute if the lk supports */ + bfad_fc_host_init(im_port); + return 0; out_fc_rel: @@ -700,9 +713,6 @@ bfad_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad) else sht = &bfad_im_vport_template; - if (max_xfer_size != BFAD_MAX_SECTORS >> 1) - sht->max_sectors = max_xfer_size << 1; - sht->sg_tablesize = bfad->cfg_data.io_max_sge; return scsi_host_alloc(sht, sizeof(unsigned long)); @@ -780,8 +790,7 @@ struct scsi_host_template bfad_im_scsi_host_template = { .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = bfad_im_host_attrs, - .max_sectors = BFAD_MAX_SECTORS, - .vendor_id = BFA_PCI_VENDOR_ID_BROCADE, + .max_sectors = 0xFFFF, }; struct scsi_host_template bfad_im_vport_template = { @@ -802,7 +811,7 @@ struct scsi_host_template bfad_im_vport_template = { .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = bfad_im_vport_attrs, - .max_sectors = BFAD_MAX_SECTORS, + .max_sectors = 0xFFFF, }; bfa_status_t @@ -916,10 +925,7 @@ bfad_im_supported_speeds(struct bfa_s *bfa) return 0; bfa_ioc_get_attr(&bfa->ioc, ioc_attr); - if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_16GBPS) - supported_speed |= FC_PORTSPEED_16GBIT | FC_PORTSPEED_8GBIT | - FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT; - else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) { + if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) { if (ioc_attr->adapter_attr.is_mezz) { supported_speed |= FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | diff --git a/trunk/drivers/scsi/bfa/bfad_im.h b/trunk/drivers/scsi/bfa/bfad_im.h index 4fe34d576b05..c296c8968511 100644 --- a/trunk/drivers/scsi/bfa/bfad_im.h +++ b/trunk/drivers/scsi/bfa/bfad_im.h @@ -141,7 +141,4 @@ extern struct device_attribute *bfad_im_vport_attrs[]; irqreturn_t bfad_intx(int irq, void *dev_id); -int bfad_im_bsg_request(struct fc_bsg_job *job); -int bfad_im_bsg_timeout(struct fc_bsg_job *job); - #endif diff --git a/trunk/drivers/scsi/bfa/bfi.h b/trunk/drivers/scsi/bfa/bfi.h index 1e258d5f8aec..72b69a0c3b51 100644 --- a/trunk/drivers/scsi/bfa/bfi.h +++ b/trunk/drivers/scsi/bfa/bfi.h @@ -23,29 +23,17 @@ #pragma pack(1) -/* Per dma segment max size */ -#define BFI_MEM_DMA_SEG_SZ (131072) - -/* Get number of dma segments required */ -#define BFI_MEM_DMA_NSEGS(_num_reqs, _req_sz) \ - ((u16)(((((_num_reqs) * (_req_sz)) + BFI_MEM_DMA_SEG_SZ - 1) & \ - ~(BFI_MEM_DMA_SEG_SZ - 1)) / BFI_MEM_DMA_SEG_SZ)) - -/* Get num dma reqs - that fit in a segment */ -#define BFI_MEM_NREQS_SEG(_rqsz) (BFI_MEM_DMA_SEG_SZ / (_rqsz)) - -/* Get segment num from tag */ -#define BFI_MEM_SEG_FROM_TAG(_tag, _rqsz) ((_tag) / BFI_MEM_NREQS_SEG(_rqsz)) - -/* Get dma req offset in a segment */ -#define BFI_MEM_SEG_REQ_OFFSET(_tag, _sz) \ - ((_tag) - (BFI_MEM_SEG_FROM_TAG(_tag, _sz) * BFI_MEM_NREQS_SEG(_sz))) - /* * BFI FW image type */ #define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */ #define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32)) +enum { + BFI_IMAGE_CB_FC, + BFI_IMAGE_CT_FC, + BFI_IMAGE_CT_CNA, + BFI_IMAGE_MAX, +}; /* * Msg header common to all msgs @@ -55,20 +43,17 @@ struct bfi_mhdr_s { u8 msg_id; /* msg opcode with in the class */ union { struct { - u8 qid; - u8 fn_lpu; /* msg destination */ + u8 rsvd; + u8 lpu_id; /* msg destination */ } h2i; u16 i2htok; /* token in msgs to host */ } mtag; }; -#define bfi_fn_lpu(__fn, __lpu) ((__fn) << 1 | (__lpu)) -#define bfi_mhdr_2_fn(_mh) ((_mh)->mtag.h2i.fn_lpu >> 1) - -#define bfi_h2i_set(_mh, _mc, _op, _fn_lpu) do { \ +#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do { \ (_mh).msg_class = (_mc); \ (_mh).msg_id = (_op); \ - (_mh).mtag.h2i.fn_lpu = (_fn_lpu); \ + (_mh).mtag.h2i.lpu_id = (_lpuid); \ } while (0) #define bfi_i2h_set(_mh, _mc, _op, _i2htok) do { \ @@ -116,7 +101,7 @@ union bfi_addr_u { }; /* - * Scatter Gather Element used for fast-path IO requests + * Scatter Gather Element */ struct bfi_sge_s { #ifdef __BIG_ENDIAN @@ -131,14 +116,6 @@ struct bfi_sge_s { union bfi_addr_u sga; }; -/** - * Generic DMA addr-len pair. - */ -struct bfi_alen_s { - union bfi_addr_u al_addr; /* DMA addr of buffer */ - u32 al_len; /* length of buffer */ -}; - /* * Scatter Gather Page */ @@ -150,12 +127,6 @@ struct bfi_sgpg_s { u32 rsvd[BFI_SGPG_RSVD_WD_LEN]; }; -/* FCP module definitions */ -#define BFI_IO_MAX (2000) -#define BFI_IOIM_SNSLEN (256) -#define BFI_IOIM_SNSBUF_SEGS \ - BFI_MEM_DMA_NSEGS(BFI_IO_MAX, BFI_IOIM_SNSLEN) - /* * Large Message structure - 128 Bytes size Msgs */ @@ -177,30 +148,19 @@ struct bfi_mbmsg_s { u32 pl[BFI_MBMSG_SZ]; }; -/* - * Supported PCI function class codes (personality) - */ -enum bfi_pcifn_class { - BFI_PCIFN_CLASS_FC = 0x0c04, - BFI_PCIFN_CLASS_ETH = 0x0200, -}; - /* * Message Classes */ enum bfi_mclass { BFI_MC_IOC = 1, /* IO Controller (IOC) */ - BFI_MC_DIAG = 2, /* Diagnostic Msgs */ - BFI_MC_FLASH = 3, /* Flash message class */ - BFI_MC_CEE = 4, /* CEE */ BFI_MC_FCPORT = 5, /* FC port */ BFI_MC_IOCFC = 6, /* FC - IO Controller (IOC) */ - BFI_MC_ABLK = 7, /* ASIC block configuration */ + BFI_MC_LL = 7, /* Link Layer */ BFI_MC_UF = 8, /* Unsolicited frame receive */ BFI_MC_FCXP = 9, /* FC Transport */ BFI_MC_LPS = 10, /* lport fc login services */ BFI_MC_RPORT = 11, /* Remote port */ - BFI_MC_ITN = 12, /* I-T nexus (Initiator mode) */ + BFI_MC_ITNIM = 12, /* I-T nexus (Initiator mode) */ BFI_MC_IOIM_READ = 13, /* read IO (Initiator mode) */ BFI_MC_IOIM_WRITE = 14, /* write IO (Initiator mode) */ BFI_MC_IOIM_IO = 15, /* IO (Initiator mode) */ @@ -208,8 +168,6 @@ enum bfi_mclass { BFI_MC_IOIM_IOCOM = 17, /* good IO completion */ BFI_MC_TSKIM = 18, /* Initiator Task management */ BFI_MC_PORT = 21, /* Physical port */ - BFI_MC_SFP = 22, /* SFP module */ - BFI_MC_PHY = 25, /* External PHY message class */ BFI_MC_MAX = 32 }; @@ -217,28 +175,23 @@ enum bfi_mclass { #define BFI_IOC_MAX_CQS_ASIC 8 #define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */ +#define BFI_BOOT_TYPE_OFF 8 +#define BFI_BOOT_LOADER_OFF 12 + +#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_LOADER_BIOS 1 +#define BFI_BOOT_LOADER_UEFI 2 + /* *---------------------------------------------------------------------- * IOC *---------------------------------------------------------------------- */ -/* - * Different asic generations - */ -enum bfi_asic_gen { - BFI_ASIC_GEN_CB = 1, /* crossbow 8G FC */ - BFI_ASIC_GEN_CT = 2, /* catapult 8G FC or 10G CNA */ - BFI_ASIC_GEN_CT2 = 3, /* catapult-2 16G FC or 10G CNA */ -}; - -enum bfi_asic_mode { - BFI_ASIC_MODE_FC = 1, /* FC upto 8G speed */ - BFI_ASIC_MODE_FC16 = 2, /* FC upto 16G speed */ - BFI_ASIC_MODE_ETH = 3, /* Ethernet ports */ - BFI_ASIC_MODE_COMBO = 4, /* FC 16G and Ethernet 10G port */ -}; - enum bfi_ioc_h2i_msgs { BFI_IOC_H2I_ENABLE_REQ = 1, BFI_IOC_H2I_DISABLE_REQ = 2, @@ -251,8 +204,8 @@ enum bfi_ioc_i2h_msgs { BFI_IOC_I2H_ENABLE_REPLY = BFA_I2HM(1), BFI_IOC_I2H_DISABLE_REPLY = BFA_I2HM(2), BFI_IOC_I2H_GETATTR_REPLY = BFA_I2HM(3), - BFI_IOC_I2H_HBEAT = BFA_I2HM(4), - BFI_IOC_I2H_ACQ_ADDR_REPLY = BFA_I2HM(5), + BFI_IOC_I2H_READY_EVENT = BFA_I2HM(4), + BFI_IOC_I2H_HBEAT = BFA_I2HM(5), }; /* @@ -267,8 +220,7 @@ struct bfi_ioc_attr_s { wwn_t mfg_pwwn; /* Mfg port wwn */ wwn_t mfg_nwwn; /* Mfg node wwn */ mac_t mfg_mac; /* Mfg mac */ - u8 port_mode; /* bfi_port_mode */ - u8 rsvd_a; + u16 rsvd_a; wwn_t pwwn; wwn_t nwwn; mac_t mac; /* PBC or Mfg mac */ @@ -320,33 +272,21 @@ struct bfi_ioc_getattr_reply_s { #define BFI_IOC_FW_SIGNATURE (0xbfadbfad) #define BFI_IOC_MD5SUM_SZ 4 struct bfi_ioc_image_hdr_s { - u32 signature; /* constant signature */ - u8 asic_gen; /* asic generation */ - u8 asic_mode; - u8 port0_mode; /* device mode for port 0 */ - u8 port1_mode; /* device mode for port 1 */ - u32 exec; /* exec vector */ - u32 bootenv; /* fimware boot env */ + u32 signature; /* constant signature */ + u32 rsvd_a; + u32 exec; /* exec vector */ + u32 param; /* parameters */ u32 rsvd_b[4]; u32 md5sum[BFI_IOC_MD5SUM_SZ]; }; -#define BFI_FWBOOT_DEVMODE_OFF 4 -#define BFI_FWBOOT_TYPE_OFF 8 -#define BFI_FWBOOT_ENV_OFF 12 -#define BFI_FWBOOT_DEVMODE(__asic_gen, __asic_mode, __p0_mode, __p1_mode) \ - (((u32)(__asic_gen)) << 24 | \ - ((u32)(__asic_mode)) << 16 | \ - ((u32)(__p0_mode)) << 8 | \ - ((u32)(__p1_mode))) - -#define BFI_FWBOOT_TYPE_NORMAL 0 -#define BFI_FWBOOT_TYPE_MEMTEST 2 -#define BFI_FWBOOT_ENV_OS 0 - -enum bfi_port_mode { - BFI_PORT_MODE_FC = 1, - BFI_PORT_MODE_ETH = 2, +/* + * BFI_IOC_I2H_READY_EVENT message + */ +struct bfi_ioc_rdy_event_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 init_status; /* init event status */ + u8 rsvd[3]; }; struct bfi_ioc_hbeat_s { @@ -405,8 +345,8 @@ enum { */ struct bfi_ioc_ctrl_req_s { struct bfi_mhdr_s mh; - u16 clscode; - u16 rsvd; + u8 ioc_class; + u8 rsvd[3]; u32 tv_sec; }; #define bfi_ioc_enable_req_t struct bfi_ioc_ctrl_req_s; @@ -418,9 +358,7 @@ struct bfi_ioc_ctrl_req_s { struct bfi_ioc_ctrl_reply_s { struct bfi_mhdr_s mh; /* Common msg header */ u8 status; /* enable/disable status */ - u8 port_mode; /* bfa_mode_s */ - u8 cap_bm; /* capability bit mask */ - u8 rsvd; + u8 rsvd[3]; }; #define bfi_ioc_enable_reply_t struct bfi_ioc_ctrl_reply_s; #define bfi_ioc_disable_reply_t struct bfi_ioc_ctrl_reply_s; @@ -442,7 +380,7 @@ union bfi_ioc_h2i_msg_u { */ union bfi_ioc_i2h_msg_u { struct bfi_mhdr_s mh; - struct bfi_ioc_ctrl_reply_s fw_event; + struct bfi_ioc_rdy_event_s rdy_event; u32 mboxmsg[BFI_IOC_MSGSZ]; }; @@ -455,7 +393,6 @@ union bfi_ioc_i2h_msg_u { #define BFI_PBC_MAX_BLUNS 8 #define BFI_PBC_MAX_VPORTS 16 -#define BFI_PBC_PORT_DISABLED 2 /* * PBC boot lun configuration @@ -637,496 +574,6 @@ union bfi_port_i2h_msg_u { struct bfi_port_generic_rsp_s clearstats_rsp; }; -/* - *---------------------------------------------------------------------- - * ABLK - *---------------------------------------------------------------------- - */ -enum bfi_ablk_h2i_msgs_e { - BFI_ABLK_H2I_QUERY = 1, - BFI_ABLK_H2I_ADPT_CONFIG = 2, - BFI_ABLK_H2I_PORT_CONFIG = 3, - BFI_ABLK_H2I_PF_CREATE = 4, - BFI_ABLK_H2I_PF_DELETE = 5, - BFI_ABLK_H2I_PF_UPDATE = 6, - BFI_ABLK_H2I_OPTROM_ENABLE = 7, - BFI_ABLK_H2I_OPTROM_DISABLE = 8, -}; - -enum bfi_ablk_i2h_msgs_e { - BFI_ABLK_I2H_QUERY = BFA_I2HM(BFI_ABLK_H2I_QUERY), - BFI_ABLK_I2H_ADPT_CONFIG = BFA_I2HM(BFI_ABLK_H2I_ADPT_CONFIG), - BFI_ABLK_I2H_PORT_CONFIG = BFA_I2HM(BFI_ABLK_H2I_PORT_CONFIG), - BFI_ABLK_I2H_PF_CREATE = BFA_I2HM(BFI_ABLK_H2I_PF_CREATE), - BFI_ABLK_I2H_PF_DELETE = BFA_I2HM(BFI_ABLK_H2I_PF_DELETE), - BFI_ABLK_I2H_PF_UPDATE = BFA_I2HM(BFI_ABLK_H2I_PF_UPDATE), - BFI_ABLK_I2H_OPTROM_ENABLE = BFA_I2HM(BFI_ABLK_H2I_OPTROM_ENABLE), - BFI_ABLK_I2H_OPTROM_DISABLE = BFA_I2HM(BFI_ABLK_H2I_OPTROM_DISABLE), -}; - -/* BFI_ABLK_H2I_QUERY */ -struct bfi_ablk_h2i_query_s { - struct bfi_mhdr_s mh; - union bfi_addr_u addr; -}; - -/* BFI_ABL_H2I_ADPT_CONFIG, BFI_ABLK_H2I_PORT_CONFIG */ -struct bfi_ablk_h2i_cfg_req_s { - struct bfi_mhdr_s mh; - u8 mode; - u8 port; - u8 max_pf; - u8 max_vf; -}; - -/* - * BFI_ABLK_H2I_PF_CREATE, BFI_ABLK_H2I_PF_DELETE, - */ -struct bfi_ablk_h2i_pf_req_s { - struct bfi_mhdr_s mh; - u8 pcifn; - u8 port; - u16 pers; - u32 bw; -}; - -/* BFI_ABLK_H2I_OPTROM_ENABLE, BFI_ABLK_H2I_OPTROM_DISABLE */ -struct bfi_ablk_h2i_optrom_s { - struct bfi_mhdr_s mh; -}; - -/* - * BFI_ABLK_I2H_QUERY - * BFI_ABLK_I2H_PORT_CONFIG - * BFI_ABLK_I2H_PF_CREATE - * BFI_ABLK_I2H_PF_DELETE - * BFI_ABLK_I2H_PF_UPDATE - * BFI_ABLK_I2H_OPTROM_ENABLE - * BFI_ABLK_I2H_OPTROM_DISABLE - */ -struct bfi_ablk_i2h_rsp_s { - struct bfi_mhdr_s mh; - u8 status; - u8 pcifn; - u8 port_mode; -}; - - -/* - * CEE module specific messages - */ - -/* Mailbox commands from host to firmware */ -enum bfi_cee_h2i_msgs_e { - BFI_CEE_H2I_GET_CFG_REQ = 1, - BFI_CEE_H2I_RESET_STATS = 2, - BFI_CEE_H2I_GET_STATS_REQ = 3, -}; - -enum bfi_cee_i2h_msgs_e { - BFI_CEE_I2H_GET_CFG_RSP = BFA_I2HM(1), - BFI_CEE_I2H_RESET_STATS_RSP = BFA_I2HM(2), - BFI_CEE_I2H_GET_STATS_RSP = BFA_I2HM(3), -}; - -/* - * H2I command structure for resetting the stats - */ -struct bfi_cee_reset_stats_s { - struct bfi_mhdr_s mh; -}; - -/* - * Get configuration command from host - */ -struct bfi_cee_get_req_s { - struct bfi_mhdr_s mh; - union bfi_addr_u dma_addr; -}; - -/* - * Reply message from firmware - */ -struct bfi_cee_get_rsp_s { - struct bfi_mhdr_s mh; - u8 cmd_status; - u8 rsvd[3]; -}; - -/* - * Reply message from firmware - */ -struct bfi_cee_stats_rsp_s { - struct bfi_mhdr_s mh; - u8 cmd_status; - u8 rsvd[3]; -}; - -/* Mailbox message structures from firmware to host */ -union bfi_cee_i2h_msg_u { - struct bfi_mhdr_s mh; - struct bfi_cee_get_rsp_s get_rsp; - struct bfi_cee_stats_rsp_s stats_rsp; -}; - -/* - * SFP related - */ - -enum bfi_sfp_h2i_e { - BFI_SFP_H2I_SHOW = 1, - BFI_SFP_H2I_SCN = 2, -}; - -enum bfi_sfp_i2h_e { - BFI_SFP_I2H_SHOW = BFA_I2HM(BFI_SFP_H2I_SHOW), - BFI_SFP_I2H_SCN = BFA_I2HM(BFI_SFP_H2I_SCN), -}; - -/* - * SFP state - */ -enum bfa_sfp_stat_e { - BFA_SFP_STATE_INIT = 0, /* SFP state is uninit */ - BFA_SFP_STATE_REMOVED = 1, /* SFP is removed */ - BFA_SFP_STATE_INSERTED = 2, /* SFP is inserted */ - BFA_SFP_STATE_VALID = 3, /* SFP is valid */ - BFA_SFP_STATE_UNSUPPORT = 4, /* SFP is unsupport */ - BFA_SFP_STATE_FAILED = 5, /* SFP i2c read fail */ -}; - -/* - * SFP memory access type - */ -enum bfi_sfp_mem_e { - BFI_SFP_MEM_ALL = 0x1, /* access all data field */ - BFI_SFP_MEM_DIAGEXT = 0x2, /* access diag ext data field only */ -}; - -struct bfi_sfp_req_s { - struct bfi_mhdr_s mh; - u8 memtype; - u8 rsvd[3]; - struct bfi_alen_s alen; -}; - -struct bfi_sfp_rsp_s { - struct bfi_mhdr_s mh; - u8 status; - u8 state; - u8 rsvd[2]; -}; - -/* - * FLASH module specific - */ -enum bfi_flash_h2i_msgs { - BFI_FLASH_H2I_QUERY_REQ = 1, - BFI_FLASH_H2I_ERASE_REQ = 2, - BFI_FLASH_H2I_WRITE_REQ = 3, - BFI_FLASH_H2I_READ_REQ = 4, - BFI_FLASH_H2I_BOOT_VER_REQ = 5, -}; - -enum bfi_flash_i2h_msgs { - BFI_FLASH_I2H_QUERY_RSP = BFA_I2HM(1), - BFI_FLASH_I2H_ERASE_RSP = BFA_I2HM(2), - BFI_FLASH_I2H_WRITE_RSP = BFA_I2HM(3), - BFI_FLASH_I2H_READ_RSP = BFA_I2HM(4), - BFI_FLASH_I2H_BOOT_VER_RSP = BFA_I2HM(5), - BFI_FLASH_I2H_EVENT = BFA_I2HM(127), -}; - -/* - * Flash query request - */ -struct bfi_flash_query_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - struct bfi_alen_s alen; -}; - -/* - * Flash erase request - */ -struct bfi_flash_erase_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; -}; - -/* - * Flash write request - */ -struct bfi_flash_write_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - struct bfi_alen_s alen; - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 last; - u8 rsv[2]; - u32 offset; - u32 length; -}; - -/* - * Flash read request - */ -struct bfi_flash_read_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 offset; - u32 length; - struct bfi_alen_s alen; -}; - -/* - * Flash query response - */ -struct bfi_flash_query_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; -}; - -/* - * Flash read response - */ -struct bfi_flash_read_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 status; - u32 length; -}; - -/* - * Flash write response - */ -struct bfi_flash_write_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 status; - u32 length; -}; - -/* - * Flash erase response - */ -struct bfi_flash_erase_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 status; -}; - -/* - *---------------------------------------------------------------------- - * DIAG - *---------------------------------------------------------------------- - */ -enum bfi_diag_h2i { - BFI_DIAG_H2I_PORTBEACON = 1, - BFI_DIAG_H2I_LOOPBACK = 2, - BFI_DIAG_H2I_FWPING = 3, - BFI_DIAG_H2I_TEMPSENSOR = 4, - BFI_DIAG_H2I_LEDTEST = 5, - BFI_DIAG_H2I_QTEST = 6, -}; - -enum bfi_diag_i2h { - BFI_DIAG_I2H_PORTBEACON = BFA_I2HM(BFI_DIAG_H2I_PORTBEACON), - BFI_DIAG_I2H_LOOPBACK = BFA_I2HM(BFI_DIAG_H2I_LOOPBACK), - BFI_DIAG_I2H_FWPING = BFA_I2HM(BFI_DIAG_H2I_FWPING), - BFI_DIAG_I2H_TEMPSENSOR = BFA_I2HM(BFI_DIAG_H2I_TEMPSENSOR), - BFI_DIAG_I2H_LEDTEST = BFA_I2HM(BFI_DIAG_H2I_LEDTEST), - BFI_DIAG_I2H_QTEST = BFA_I2HM(BFI_DIAG_H2I_QTEST), -}; - -#define BFI_DIAG_MAX_SGES 2 -#define BFI_DIAG_DMA_BUF_SZ (2 * 1024) -#define BFI_BOOT_MEMTEST_RES_ADDR 0x900 -#define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3 - -struct bfi_diag_lb_req_s { - struct bfi_mhdr_s mh; - u32 loopcnt; - u32 pattern; - u8 lb_mode; /*!< bfa_port_opmode_t */ - u8 speed; /*!< bfa_port_speed_t */ - u8 rsvd[2]; -}; - -struct bfi_diag_lb_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - struct bfa_diag_loopback_result_s res; /* 16 bytes */ -}; - -struct bfi_diag_fwping_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - struct bfi_alen_s alen; /* 12 bytes */ - u32 data; /* user input data pattern */ - u32 count; /* user input dma count */ - u8 qtag; /* track CPE vc */ - u8 rsv[3]; -}; - -struct bfi_diag_fwping_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u32 data; /* user input data pattern */ - u8 qtag; /* track CPE vc */ - u8 dma_status; /* dma status */ - u8 rsv[2]; -}; - -/* - * Temperature Sensor - */ -struct bfi_diag_ts_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u16 temp; /* 10-bit A/D value */ - u16 brd_temp; /* 9-bit board temp */ - u8 status; - u8 ts_junc; /* show junction tempsensor */ - u8 ts_brd; /* show board tempsensor */ - u8 rsv; -}; -#define bfi_diag_ts_rsp_t struct bfi_diag_ts_req_s - -struct bfi_diag_ledtest_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u8 cmd; - u8 color; - u8 portid; - u8 led; /* bitmap of LEDs to be tested */ - u16 freq; /* no. of blinks every 10 secs */ - u8 rsv[2]; -}; - -/* notify host led operation is done */ -struct bfi_diag_ledtest_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ -}; - -struct bfi_diag_portbeacon_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u32 period; /* beaconing period */ - u8 beacon; /* 1: beacon on */ - u8 rsvd[3]; -}; - -/* notify host the beacon is off */ -struct bfi_diag_portbeacon_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ -}; - -struct bfi_diag_qtest_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u32 data[BFI_LMSG_PL_WSZ]; /* fill up tcm prefetch area */ -}; -#define bfi_diag_qtest_rsp_t struct bfi_diag_qtest_req_s - -/* - * PHY module specific - */ -enum bfi_phy_h2i_msgs_e { - BFI_PHY_H2I_QUERY_REQ = 1, - BFI_PHY_H2I_STATS_REQ = 2, - BFI_PHY_H2I_WRITE_REQ = 3, - BFI_PHY_H2I_READ_REQ = 4, -}; - -enum bfi_phy_i2h_msgs_e { - BFI_PHY_I2H_QUERY_RSP = BFA_I2HM(1), - BFI_PHY_I2H_STATS_RSP = BFA_I2HM(2), - BFI_PHY_I2H_WRITE_RSP = BFA_I2HM(3), - BFI_PHY_I2H_READ_RSP = BFA_I2HM(4), -}; - -/* - * External PHY query request - */ -struct bfi_phy_query_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 rsv[3]; - struct bfi_alen_s alen; -}; - -/* - * External PHY stats request - */ -struct bfi_phy_stats_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 rsv[3]; - struct bfi_alen_s alen; -}; - -/* - * External PHY write request - */ -struct bfi_phy_write_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 last; - u8 rsv[2]; - u32 offset; - u32 length; - struct bfi_alen_s alen; -}; - -/* - * External PHY read request - */ -struct bfi_phy_read_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 rsv[3]; - u32 offset; - u32 length; - struct bfi_alen_s alen; -}; - -/* - * External PHY query response - */ -struct bfi_phy_query_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; -}; - -/* - * External PHY stats response - */ -struct bfi_phy_stats_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; -}; - -/* - * External PHY read response - */ -struct bfi_phy_read_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; - u32 length; -}; - -/* - * External PHY write response - */ -struct bfi_phy_write_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; - u32 length; -}; - #pragma pack() #endif /* __BFI_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfi_cbreg.h b/trunk/drivers/scsi/bfa/bfi_cbreg.h new file mode 100644 index 000000000000..39ad42b66b5b --- /dev/null +++ b/trunk/drivers/scsi/bfa/bfi_cbreg.h @@ -0,0 +1,305 @@ + +/* + * bfi_cbreg.h crossbow host block register definitions + * + * !!! Do not edit. Auto generated. !!! + */ + +#ifndef __BFI_CBREG_H__ +#define __BFI_CBREG_H__ + + +#define HOSTFN0_INT_STATUS 0x00014000 +#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN0_INT_STATUS_LVL_SH 20 +#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH) +#define __HOSTFN0_INT_STATUS_P 0x000fffff +#define HOSTFN0_INT_MSK 0x00014004 +#define HOST_PAGE_NUM_FN0 0x00014008 +#define __HOST_PAGE_NUM_FN 0x000001ff +#define HOSTFN1_INT_STATUS 0x00014100 +#define __HOSTFN1_INT_STAT_LVL_MK 0x00f00000 +#define __HOSTFN1_INT_STAT_LVL_SH 20 +#define __HOSTFN1_INT_STAT_LVL(_v) ((_v) << __HOSTFN1_INT_STAT_LVL_SH) +#define __HOSTFN1_INT_STAT_P 0x000fffff +#define HOSTFN1_INT_MSK 0x00014104 +#define HOST_PAGE_NUM_FN1 0x00014108 +#define APP_PLL_400_CTL_REG 0x00014204 +#define __P_400_PLL_LOCK 0x80000000 +#define __APP_PLL_400_SRAM_USE_100MHZ 0x00100000 +#define __APP_PLL_400_RESET_TIMER_MK 0x000e0000 +#define __APP_PLL_400_RESET_TIMER_SH 17 +#define __APP_PLL_400_RESET_TIMER(_v) ((_v) << __APP_PLL_400_RESET_TIMER_SH) +#define __APP_PLL_400_LOGIC_SOFT_RESET 0x00010000 +#define __APP_PLL_400_CNTLMT0_1_MK 0x0000c000 +#define __APP_PLL_400_CNTLMT0_1_SH 14 +#define __APP_PLL_400_CNTLMT0_1(_v) ((_v) << __APP_PLL_400_CNTLMT0_1_SH) +#define __APP_PLL_400_JITLMT0_1_MK 0x00003000 +#define __APP_PLL_400_JITLMT0_1_SH 12 +#define __APP_PLL_400_JITLMT0_1(_v) ((_v) << __APP_PLL_400_JITLMT0_1_SH) +#define __APP_PLL_400_HREF 0x00000800 +#define __APP_PLL_400_HDIV 0x00000400 +#define __APP_PLL_400_P0_1_MK 0x00000300 +#define __APP_PLL_400_P0_1_SH 8 +#define __APP_PLL_400_P0_1(_v) ((_v) << __APP_PLL_400_P0_1_SH) +#define __APP_PLL_400_Z0_2_MK 0x000000e0 +#define __APP_PLL_400_Z0_2_SH 5 +#define __APP_PLL_400_Z0_2(_v) ((_v) << __APP_PLL_400_Z0_2_SH) +#define __APP_PLL_400_RSEL200500 0x00000010 +#define __APP_PLL_400_ENARST 0x00000008 +#define __APP_PLL_400_BYPASS 0x00000004 +#define __APP_PLL_400_LRESETN 0x00000002 +#define __APP_PLL_400_ENABLE 0x00000001 +#define APP_PLL_212_CTL_REG 0x00014208 +#define __P_212_PLL_LOCK 0x80000000 +#define __APP_PLL_212_RESET_TIMER_MK 0x000e0000 +#define __APP_PLL_212_RESET_TIMER_SH 17 +#define __APP_PLL_212_RESET_TIMER(_v) ((_v) << __APP_PLL_212_RESET_TIMER_SH) +#define __APP_PLL_212_LOGIC_SOFT_RESET 0x00010000 +#define __APP_PLL_212_CNTLMT0_1_MK 0x0000c000 +#define __APP_PLL_212_CNTLMT0_1_SH 14 +#define __APP_PLL_212_CNTLMT0_1(_v) ((_v) << __APP_PLL_212_CNTLMT0_1_SH) +#define __APP_PLL_212_JITLMT0_1_MK 0x00003000 +#define __APP_PLL_212_JITLMT0_1_SH 12 +#define __APP_PLL_212_JITLMT0_1(_v) ((_v) << __APP_PLL_212_JITLMT0_1_SH) +#define __APP_PLL_212_HREF 0x00000800 +#define __APP_PLL_212_HDIV 0x00000400 +#define __APP_PLL_212_P0_1_MK 0x00000300 +#define __APP_PLL_212_P0_1_SH 8 +#define __APP_PLL_212_P0_1(_v) ((_v) << __APP_PLL_212_P0_1_SH) +#define __APP_PLL_212_Z0_2_MK 0x000000e0 +#define __APP_PLL_212_Z0_2_SH 5 +#define __APP_PLL_212_Z0_2(_v) ((_v) << __APP_PLL_212_Z0_2_SH) +#define __APP_PLL_212_RSEL200500 0x00000010 +#define __APP_PLL_212_ENARST 0x00000008 +#define __APP_PLL_212_BYPASS 0x00000004 +#define __APP_PLL_212_LRESETN 0x00000002 +#define __APP_PLL_212_ENABLE 0x00000001 +#define HOST_SEM0_REG 0x00014230 +#define __HOST_SEMAPHORE 0x00000001 +#define HOST_SEM1_REG 0x00014234 +#define HOST_SEM2_REG 0x00014238 +#define HOST_SEM3_REG 0x0001423c +#define HOST_SEM0_INFO_REG 0x00014240 +#define HOST_SEM1_INFO_REG 0x00014244 +#define HOST_SEM2_INFO_REG 0x00014248 +#define HOST_SEM3_INFO_REG 0x0001424c +#define HOSTFN0_LPU0_CMD_STAT 0x00019000 +#define __HOSTFN0_LPU0_MBOX_INFO_MK 0xfffffffe +#define __HOSTFN0_LPU0_MBOX_INFO_SH 1 +#define __HOSTFN0_LPU0_MBOX_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX_INFO_SH) +#define __HOSTFN0_LPU0_MBOX_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN0_CMD_STAT 0x00019008 +#define __LPU0_HOSTFN0_MBOX_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN0_MBOX_INFO_SH 1 +#define __LPU0_HOSTFN0_MBOX_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX_INFO_SH) +#define __LPU0_HOSTFN0_MBOX_CMD_STATUS 0x00000001 +#define HOSTFN1_LPU1_CMD_STAT 0x00019014 +#define __HOSTFN1_LPU1_MBOX_INFO_MK 0xfffffffe +#define __HOSTFN1_LPU1_MBOX_INFO_SH 1 +#define __HOSTFN1_LPU1_MBOX_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX_INFO_SH) +#define __HOSTFN1_LPU1_MBOX_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN1_CMD_STAT 0x0001901c +#define __LPU1_HOSTFN1_MBOX_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN1_MBOX_INFO_SH 1 +#define __LPU1_HOSTFN1_MBOX_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX_INFO_SH) +#define __LPU1_HOSTFN1_MBOX_CMD_STATUS 0x00000001 +#define CPE_Q0_DEPTH 0x00010014 +#define CPE_Q0_PI 0x0001001c +#define CPE_Q0_CI 0x00010020 +#define CPE_Q1_DEPTH 0x00010034 +#define CPE_Q1_PI 0x0001003c +#define CPE_Q1_CI 0x00010040 +#define CPE_Q2_DEPTH 0x00010054 +#define CPE_Q2_PI 0x0001005c +#define CPE_Q2_CI 0x00010060 +#define CPE_Q3_DEPTH 0x00010074 +#define CPE_Q3_PI 0x0001007c +#define CPE_Q3_CI 0x00010080 +#define CPE_Q4_DEPTH 0x00010094 +#define CPE_Q4_PI 0x0001009c +#define CPE_Q4_CI 0x000100a0 +#define CPE_Q5_DEPTH 0x000100b4 +#define CPE_Q5_PI 0x000100bc +#define CPE_Q5_CI 0x000100c0 +#define CPE_Q6_DEPTH 0x000100d4 +#define CPE_Q6_PI 0x000100dc +#define CPE_Q6_CI 0x000100e0 +#define CPE_Q7_DEPTH 0x000100f4 +#define CPE_Q7_PI 0x000100fc +#define CPE_Q7_CI 0x00010100 +#define RME_Q0_DEPTH 0x00011014 +#define RME_Q0_PI 0x0001101c +#define RME_Q0_CI 0x00011020 +#define RME_Q1_DEPTH 0x00011034 +#define RME_Q1_PI 0x0001103c +#define RME_Q1_CI 0x00011040 +#define RME_Q2_DEPTH 0x00011054 +#define RME_Q2_PI 0x0001105c +#define RME_Q2_CI 0x00011060 +#define RME_Q3_DEPTH 0x00011074 +#define RME_Q3_PI 0x0001107c +#define RME_Q3_CI 0x00011080 +#define RME_Q4_DEPTH 0x00011094 +#define RME_Q4_PI 0x0001109c +#define RME_Q4_CI 0x000110a0 +#define RME_Q5_DEPTH 0x000110b4 +#define RME_Q5_PI 0x000110bc +#define RME_Q5_CI 0x000110c0 +#define RME_Q6_DEPTH 0x000110d4 +#define RME_Q6_PI 0x000110dc +#define RME_Q6_CI 0x000110e0 +#define RME_Q7_DEPTH 0x000110f4 +#define RME_Q7_PI 0x000110fc +#define RME_Q7_CI 0x00011100 +#define PSS_CTL_REG 0x00018800 +#define __PSS_I2C_CLK_DIV_MK 0x00030000 +#define __PSS_I2C_CLK_DIV_SH 16 +#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH) +#define __PSS_LMEM_INIT_DONE 0x00001000 +#define __PSS_LMEM_RESET 0x00000200 +#define __PSS_LMEM_INIT_EN 0x00000100 +#define __PSS_LPU1_RESET 0x00000002 +#define __PSS_LPU0_RESET 0x00000001 +#define PSS_ERR_STATUS_REG 0x00018810 +#define __PSS_LMEM1_CORR_ERR 0x00000800 +#define __PSS_LMEM0_CORR_ERR 0x00000400 +#define __PSS_LMEM1_UNCORR_ERR 0x00000200 +#define __PSS_LMEM0_UNCORR_ERR 0x00000100 +#define __PSS_BAL_PERR 0x00000080 +#define __PSS_DIP_IF_ERR 0x00000040 +#define __PSS_IOH_IF_ERR 0x00000020 +#define __PSS_TDS_IF_ERR 0x00000010 +#define __PSS_RDS_IF_ERR 0x00000008 +#define __PSS_SGM_IF_ERR 0x00000004 +#define __PSS_LPU1_RAM_ERR 0x00000002 +#define __PSS_LPU0_RAM_ERR 0x00000001 +#define ERR_SET_REG 0x00018818 +#define __PSS_ERR_STATUS_SET 0x00000fff + + +/* + * These definitions are either in error/missing in spec. Its auto-generated + * from hard coded values in regparse.pl. + */ +#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c +#define __EMPHPOST_AT_4G_SH_FIX 0x00000002 +#define __EMPHPRE_AT_4G_FIX 0x00000003 +#define __SFP_TXRATE_EN_FIX 0x00000100 +#define __SFP_RXRATE_EN_FIX 0x00000080 + + +/* + * These register definitions are auto-generated from hard coded values + * in regparse.pl. + */ +#define HOSTFN0_LPU_MBOX0_0 0x00019200 +#define HOSTFN1_LPU_MBOX0_8 0x00019260 +#define LPU_HOSTFN0_MBOX0_0 0x00019280 +#define LPU_HOSTFN1_MBOX0_8 0x000192e0 + + +/* + * These register mapping definitions are auto-generated from mapping tables + * in regparse.pl. + */ +#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG +#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG +#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG +#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG +#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG +#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG + +#define CPE_Q_DEPTH(__n) \ + (CPE_Q0_DEPTH + (__n) * (CPE_Q1_DEPTH - CPE_Q0_DEPTH)) +#define CPE_Q_PI(__n) \ + (CPE_Q0_PI + (__n) * (CPE_Q1_PI - CPE_Q0_PI)) +#define CPE_Q_CI(__n) \ + (CPE_Q0_CI + (__n) * (CPE_Q1_CI - CPE_Q0_CI)) +#define RME_Q_DEPTH(__n) \ + (RME_Q0_DEPTH + (__n) * (RME_Q1_DEPTH - RME_Q0_DEPTH)) +#define RME_Q_PI(__n) \ + (RME_Q0_PI + (__n) * (RME_Q1_PI - RME_Q0_PI)) +#define RME_Q_CI(__n) \ + (RME_Q0_CI + (__n) * (RME_Q1_CI - RME_Q0_CI)) + +#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) +#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) +#define CPE_Q_MASK(__q) ((__q) & 0x3) +#define RME_Q_MASK(__q) ((__q) & 0x3) + + +/* + * PCI MSI-X vector defines + */ +enum { + BFA_MSIX_CPE_Q0 = 0, + BFA_MSIX_CPE_Q1 = 1, + BFA_MSIX_CPE_Q2 = 2, + BFA_MSIX_CPE_Q3 = 3, + BFA_MSIX_CPE_Q4 = 4, + BFA_MSIX_CPE_Q5 = 5, + BFA_MSIX_CPE_Q6 = 6, + BFA_MSIX_CPE_Q7 = 7, + BFA_MSIX_RME_Q0 = 8, + BFA_MSIX_RME_Q1 = 9, + BFA_MSIX_RME_Q2 = 10, + BFA_MSIX_RME_Q3 = 11, + BFA_MSIX_RME_Q4 = 12, + BFA_MSIX_RME_Q5 = 13, + BFA_MSIX_RME_Q6 = 14, + BFA_MSIX_RME_Q7 = 15, + BFA_MSIX_ERR_EMC = 16, + BFA_MSIX_ERR_LPU0 = 17, + BFA_MSIX_ERR_LPU1 = 18, + BFA_MSIX_ERR_PSS = 19, + BFA_MSIX_MBOX_LPU0 = 20, + BFA_MSIX_MBOX_LPU1 = 21, + BFA_MSIX_CB_MAX = 22, +}; + +/* + * And corresponding host interrupt status bit field defines + */ +#define __HFN_INT_CPE_Q0 0x00000001U +#define __HFN_INT_CPE_Q1 0x00000002U +#define __HFN_INT_CPE_Q2 0x00000004U +#define __HFN_INT_CPE_Q3 0x00000008U +#define __HFN_INT_CPE_Q4 0x00000010U +#define __HFN_INT_CPE_Q5 0x00000020U +#define __HFN_INT_CPE_Q6 0x00000040U +#define __HFN_INT_CPE_Q7 0x00000080U +#define __HFN_INT_RME_Q0 0x00000100U +#define __HFN_INT_RME_Q1 0x00000200U +#define __HFN_INT_RME_Q2 0x00000400U +#define __HFN_INT_RME_Q3 0x00000800U +#define __HFN_INT_RME_Q4 0x00001000U +#define __HFN_INT_RME_Q5 0x00002000U +#define __HFN_INT_RME_Q6 0x00004000U +#define __HFN_INT_RME_Q7 0x00008000U +#define __HFN_INT_ERR_EMC 0x00010000U +#define __HFN_INT_ERR_LPU0 0x00020000U +#define __HFN_INT_ERR_LPU1 0x00040000U +#define __HFN_INT_ERR_PSS 0x00080000U +#define __HFN_INT_MBOX_LPU0 0x00100000U +#define __HFN_INT_MBOX_LPU1 0x00200000U +#define __HFN_INT_MBOX1_LPU0 0x00400000U +#define __HFN_INT_MBOX1_LPU1 0x00800000U +#define __HFN_INT_CPE_MASK 0x000000ffU +#define __HFN_INT_RME_MASK 0x0000ff00U + + +/* + * crossbow memory map. + */ +#define PSS_SMEM_PAGE_START 0x8000 +#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15)) +#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff) + +/* + * End of crossbow memory map + */ + + +#endif /* __BFI_CBREG_H__ */ + diff --git a/trunk/drivers/scsi/bfa/bfi_ctreg.h b/trunk/drivers/scsi/bfa/bfi_ctreg.h new file mode 100644 index 000000000000..fc4ce4a5a183 --- /dev/null +++ b/trunk/drivers/scsi/bfa/bfi_ctreg.h @@ -0,0 +1,636 @@ + +/* + * bfi_ctreg.h catapult host block register definitions + * + * !!! Do not edit. Auto generated. !!! + */ + +#ifndef __BFI_CTREG_H__ +#define __BFI_CTREG_H__ + + +#define HOSTFN0_LPU_MBOX0_0 0x00019200 +#define HOSTFN1_LPU_MBOX0_8 0x00019260 +#define LPU_HOSTFN0_MBOX0_0 0x00019280 +#define LPU_HOSTFN1_MBOX0_8 0x000192e0 +#define HOSTFN2_LPU_MBOX0_0 0x00019400 +#define HOSTFN3_LPU_MBOX0_8 0x00019460 +#define LPU_HOSTFN2_MBOX0_0 0x00019480 +#define LPU_HOSTFN3_MBOX0_8 0x000194e0 +#define HOSTFN0_INT_STATUS 0x00014000 +#define __HOSTFN0_HALT_OCCURRED 0x01000000 +#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN0_INT_STATUS_LVL_SH 20 +#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH) +#define __HOSTFN0_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN0_INT_STATUS_P_SH 16 +#define __HOSTFN0_INT_STATUS_P(_v) ((_v) << __HOSTFN0_INT_STATUS_P_SH) +#define __HOSTFN0_INT_STATUS_F 0x0000ffff +#define HOSTFN0_INT_MSK 0x00014004 +#define HOST_PAGE_NUM_FN0 0x00014008 +#define __HOST_PAGE_NUM_FN 0x000001ff +#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c +#define __MSIX_ERR_INDEX_FN 0x000001ff +#define HOSTFN1_INT_STATUS 0x00014100 +#define __HOSTFN1_HALT_OCCURRED 0x01000000 +#define __HOSTFN1_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN1_INT_STATUS_LVL_SH 20 +#define __HOSTFN1_INT_STATUS_LVL(_v) ((_v) << __HOSTFN1_INT_STATUS_LVL_SH) +#define __HOSTFN1_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN1_INT_STATUS_P_SH 16 +#define __HOSTFN1_INT_STATUS_P(_v) ((_v) << __HOSTFN1_INT_STATUS_P_SH) +#define __HOSTFN1_INT_STATUS_F 0x0000ffff +#define HOSTFN1_INT_MSK 0x00014104 +#define HOST_PAGE_NUM_FN1 0x00014108 +#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c +#define APP_PLL_425_CTL_REG 0x00014204 +#define __P_425_PLL_LOCK 0x80000000 +#define __APP_PLL_425_SRAM_USE_100MHZ 0x00100000 +#define __APP_PLL_425_RESET_TIMER_MK 0x000e0000 +#define __APP_PLL_425_RESET_TIMER_SH 17 +#define __APP_PLL_425_RESET_TIMER(_v) ((_v) << __APP_PLL_425_RESET_TIMER_SH) +#define __APP_PLL_425_LOGIC_SOFT_RESET 0x00010000 +#define __APP_PLL_425_CNTLMT0_1_MK 0x0000c000 +#define __APP_PLL_425_CNTLMT0_1_SH 14 +#define __APP_PLL_425_CNTLMT0_1(_v) ((_v) << __APP_PLL_425_CNTLMT0_1_SH) +#define __APP_PLL_425_JITLMT0_1_MK 0x00003000 +#define __APP_PLL_425_JITLMT0_1_SH 12 +#define __APP_PLL_425_JITLMT0_1(_v) ((_v) << __APP_PLL_425_JITLMT0_1_SH) +#define __APP_PLL_425_HREF 0x00000800 +#define __APP_PLL_425_HDIV 0x00000400 +#define __APP_PLL_425_P0_1_MK 0x00000300 +#define __APP_PLL_425_P0_1_SH 8 +#define __APP_PLL_425_P0_1(_v) ((_v) << __APP_PLL_425_P0_1_SH) +#define __APP_PLL_425_Z0_2_MK 0x000000e0 +#define __APP_PLL_425_Z0_2_SH 5 +#define __APP_PLL_425_Z0_2(_v) ((_v) << __APP_PLL_425_Z0_2_SH) +#define __APP_PLL_425_RSEL200500 0x00000010 +#define __APP_PLL_425_ENARST 0x00000008 +#define __APP_PLL_425_BYPASS 0x00000004 +#define __APP_PLL_425_LRESETN 0x00000002 +#define __APP_PLL_425_ENABLE 0x00000001 +#define APP_PLL_312_CTL_REG 0x00014208 +#define __P_312_PLL_LOCK 0x80000000 +#define __ENABLE_MAC_AHB_1 0x00800000 +#define __ENABLE_MAC_AHB_0 0x00400000 +#define __ENABLE_MAC_1 0x00200000 +#define __ENABLE_MAC_0 0x00100000 +#define __APP_PLL_312_RESET_TIMER_MK 0x000e0000 +#define __APP_PLL_312_RESET_TIMER_SH 17 +#define __APP_PLL_312_RESET_TIMER(_v) ((_v) << __APP_PLL_312_RESET_TIMER_SH) +#define __APP_PLL_312_LOGIC_SOFT_RESET 0x00010000 +#define __APP_PLL_312_CNTLMT0_1_MK 0x0000c000 +#define __APP_PLL_312_CNTLMT0_1_SH 14 +#define __APP_PLL_312_CNTLMT0_1(_v) ((_v) << __APP_PLL_312_CNTLMT0_1_SH) +#define __APP_PLL_312_JITLMT0_1_MK 0x00003000 +#define __APP_PLL_312_JITLMT0_1_SH 12 +#define __APP_PLL_312_JITLMT0_1(_v) ((_v) << __APP_PLL_312_JITLMT0_1_SH) +#define __APP_PLL_312_HREF 0x00000800 +#define __APP_PLL_312_HDIV 0x00000400 +#define __APP_PLL_312_P0_1_MK 0x00000300 +#define __APP_PLL_312_P0_1_SH 8 +#define __APP_PLL_312_P0_1(_v) ((_v) << __APP_PLL_312_P0_1_SH) +#define __APP_PLL_312_Z0_2_MK 0x000000e0 +#define __APP_PLL_312_Z0_2_SH 5 +#define __APP_PLL_312_Z0_2(_v) ((_v) << __APP_PLL_312_Z0_2_SH) +#define __APP_PLL_312_RSEL200500 0x00000010 +#define __APP_PLL_312_ENARST 0x00000008 +#define __APP_PLL_312_BYPASS 0x00000004 +#define __APP_PLL_312_LRESETN 0x00000002 +#define __APP_PLL_312_ENABLE 0x00000001 +#define MBIST_CTL_REG 0x00014220 +#define __EDRAM_BISTR_START 0x00000004 +#define __MBIST_RESET 0x00000002 +#define __MBIST_START 0x00000001 +#define MBIST_STAT_REG 0x00014224 +#define __EDRAM_BISTR_STATUS 0x00000008 +#define __EDRAM_BISTR_DONE 0x00000004 +#define __MEM_BIT_STATUS 0x00000002 +#define __MBIST_DONE 0x00000001 +#define HOST_SEM0_REG 0x00014230 +#define __HOST_SEMAPHORE 0x00000001 +#define HOST_SEM1_REG 0x00014234 +#define HOST_SEM2_REG 0x00014238 +#define HOST_SEM3_REG 0x0001423c +#define HOST_SEM0_INFO_REG 0x00014240 +#define HOST_SEM1_INFO_REG 0x00014244 +#define HOST_SEM2_INFO_REG 0x00014248 +#define HOST_SEM3_INFO_REG 0x0001424c +#define ETH_MAC_SER_REG 0x00014288 +#define __APP_EMS_CKBUFAMPIN 0x00000020 +#define __APP_EMS_REFCLKSEL 0x00000010 +#define __APP_EMS_CMLCKSEL 0x00000008 +#define __APP_EMS_REFCKBUFEN2 0x00000004 +#define __APP_EMS_REFCKBUFEN1 0x00000002 +#define __APP_EMS_CHANNEL_SEL 0x00000001 +#define HOSTFN2_INT_STATUS 0x00014300 +#define __HOSTFN2_HALT_OCCURRED 0x01000000 +#define __HOSTFN2_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN2_INT_STATUS_LVL_SH 20 +#define __HOSTFN2_INT_STATUS_LVL(_v) ((_v) << __HOSTFN2_INT_STATUS_LVL_SH) +#define __HOSTFN2_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN2_INT_STATUS_P_SH 16 +#define __HOSTFN2_INT_STATUS_P(_v) ((_v) << __HOSTFN2_INT_STATUS_P_SH) +#define __HOSTFN2_INT_STATUS_F 0x0000ffff +#define HOSTFN2_INT_MSK 0x00014304 +#define HOST_PAGE_NUM_FN2 0x00014308 +#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c +#define HOSTFN3_INT_STATUS 0x00014400 +#define __HALT_OCCURRED 0x01000000 +#define __HOSTFN3_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN3_INT_STATUS_LVL_SH 20 +#define __HOSTFN3_INT_STATUS_LVL(_v) ((_v) << __HOSTFN3_INT_STATUS_LVL_SH) +#define __HOSTFN3_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN3_INT_STATUS_P_SH 16 +#define __HOSTFN3_INT_STATUS_P(_v) ((_v) << __HOSTFN3_INT_STATUS_P_SH) +#define __HOSTFN3_INT_STATUS_F 0x0000ffff +#define HOSTFN3_INT_MSK 0x00014404 +#define HOST_PAGE_NUM_FN3 0x00014408 +#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c +#define FNC_ID_REG 0x00014600 +#define __FUNCTION_NUMBER 0x00000007 +#define FNC_PERS_REG 0x00014604 +#define __F3_FUNCTION_ACTIVE 0x80000000 +#define __F3_FUNCTION_MODE 0x40000000 +#define __F3_PORT_MAP_MK 0x30000000 +#define __F3_PORT_MAP_SH 28 +#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH) +#define __F3_VM_MODE 0x08000000 +#define __F3_INTX_STATUS_MK 0x07000000 +#define __F3_INTX_STATUS_SH 24 +#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH) +#define __F2_FUNCTION_ACTIVE 0x00800000 +#define __F2_FUNCTION_MODE 0x00400000 +#define __F2_PORT_MAP_MK 0x00300000 +#define __F2_PORT_MAP_SH 20 +#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH) +#define __F2_VM_MODE 0x00080000 +#define __F2_INTX_STATUS_MK 0x00070000 +#define __F2_INTX_STATUS_SH 16 +#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH) +#define __F1_FUNCTION_ACTIVE 0x00008000 +#define __F1_FUNCTION_MODE 0x00004000 +#define __F1_PORT_MAP_MK 0x00003000 +#define __F1_PORT_MAP_SH 12 +#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH) +#define __F1_VM_MODE 0x00000800 +#define __F1_INTX_STATUS_MK 0x00000700 +#define __F1_INTX_STATUS_SH 8 +#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH) +#define __F0_FUNCTION_ACTIVE 0x00000080 +#define __F0_FUNCTION_MODE 0x00000040 +#define __F0_PORT_MAP_MK 0x00000030 +#define __F0_PORT_MAP_SH 4 +#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH) +#define __F0_VM_MODE 0x00000008 +#define __F0_INTX_STATUS 0x00000007 +enum { + __F0_INTX_STATUS_MSIX = 0x0, + __F0_INTX_STATUS_INTA = 0x1, + __F0_INTX_STATUS_INTB = 0x2, + __F0_INTX_STATUS_INTC = 0x3, + __F0_INTX_STATUS_INTD = 0x4, +}; +#define OP_MODE 0x0001460c +#define __APP_ETH_CLK_LOWSPEED 0x00000004 +#define __GLOBAL_CORECLK_HALFSPEED 0x00000002 +#define __GLOBAL_FCOE_MODE 0x00000001 +#define HOST_SEM4_REG 0x00014610 +#define HOST_SEM5_REG 0x00014614 +#define HOST_SEM6_REG 0x00014618 +#define HOST_SEM7_REG 0x0001461c +#define HOST_SEM4_INFO_REG 0x00014620 +#define HOST_SEM5_INFO_REG 0x00014624 +#define HOST_SEM6_INFO_REG 0x00014628 +#define HOST_SEM7_INFO_REG 0x0001462c +#define HOSTFN0_LPU0_MBOX0_CMD_STAT 0x00019000 +#define __HOSTFN0_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN0_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN0_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX0_INFO_SH) +#define __HOSTFN0_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN0_LPU1_MBOX0_CMD_STAT 0x00019004 +#define __HOSTFN0_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN0_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN0_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU1_MBOX0_INFO_SH) +#define __HOSTFN0_LPU1_MBOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN0_MBOX0_CMD_STAT 0x00019008 +#define __LPU0_HOSTFN0_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN0_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX0_INFO_SH) +#define __LPU0_HOSTFN0_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN0_MBOX0_CMD_STAT 0x0001900c +#define __LPU1_HOSTFN0_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN0_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN0_MBOX0_INFO_SH) +#define __LPU1_HOSTFN0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN1_LPU0_MBOX0_CMD_STAT 0x00019010 +#define __HOSTFN1_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN1_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN1_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU0_MBOX0_INFO_SH) +#define __HOSTFN1_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN1_LPU1_MBOX0_CMD_STAT 0x00019014 +#define __HOSTFN1_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN1_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN1_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX0_INFO_SH) +#define __HOSTFN1_LPU1_MBOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN1_MBOX0_CMD_STAT 0x00019018 +#define __LPU0_HOSTFN1_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN1_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN1_MBOX0_INFO_SH) +#define __LPU0_HOSTFN1_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN1_MBOX0_CMD_STAT 0x0001901c +#define __LPU1_HOSTFN1_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN1_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX0_INFO_SH) +#define __LPU1_HOSTFN1_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN2_LPU0_MBOX0_CMD_STAT 0x00019150 +#define __HOSTFN2_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN2_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN2_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU0_MBOX0_INFO_SH) +#define __HOSTFN2_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN2_LPU1_MBOX0_CMD_STAT 0x00019154 +#define __HOSTFN2_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN2_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN2_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU1_MBOX0_INFO_SH) +#define __HOSTFN2_LPU1_MBOX0BOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN2_MBOX0_CMD_STAT 0x00019158 +#define __LPU0_HOSTFN2_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN2_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN2_MBOX0_INFO_SH) +#define __LPU0_HOSTFN2_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN2_MBOX0_CMD_STAT 0x0001915c +#define __LPU1_HOSTFN2_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN2_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN2_MBOX0_INFO_SH) +#define __LPU1_HOSTFN2_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN3_LPU0_MBOX0_CMD_STAT 0x00019160 +#define __HOSTFN3_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN3_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN3_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU0_MBOX0_INFO_SH) +#define __HOSTFN3_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN3_LPU1_MBOX0_CMD_STAT 0x00019164 +#define __HOSTFN3_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN3_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN3_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU1_MBOX0_INFO_SH) +#define __HOSTFN3_LPU1_MBOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN3_MBOX0_CMD_STAT 0x00019168 +#define __LPU0_HOSTFN3_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN3_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN3_MBOX0_INFO_SH) +#define __LPU0_HOSTFN3_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN3_MBOX0_CMD_STAT 0x0001916c +#define __LPU1_HOSTFN3_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN3_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN3_MBOX0_INFO_SH) +#define __LPU1_HOSTFN3_MBOX0_CMD_STATUS 0x00000001 +#define FW_INIT_HALT_P0 0x000191ac +#define __FW_INIT_HALT_P 0x00000001 +#define FW_INIT_HALT_P1 0x000191bc +#define CPE_PI_PTR_Q0 0x00038000 +#define __CPE_PI_UNUSED_MK 0xffff0000 +#define __CPE_PI_UNUSED_SH 16 +#define __CPE_PI_UNUSED(_v) ((_v) << __CPE_PI_UNUSED_SH) +#define __CPE_PI_PTR 0x0000ffff +#define CPE_PI_PTR_Q1 0x00038040 +#define CPE_CI_PTR_Q0 0x00038004 +#define __CPE_CI_UNUSED_MK 0xffff0000 +#define __CPE_CI_UNUSED_SH 16 +#define __CPE_CI_UNUSED(_v) ((_v) << __CPE_CI_UNUSED_SH) +#define __CPE_CI_PTR 0x0000ffff +#define CPE_CI_PTR_Q1 0x00038044 +#define CPE_DEPTH_Q0 0x00038008 +#define __CPE_DEPTH_UNUSED_MK 0xf8000000 +#define __CPE_DEPTH_UNUSED_SH 27 +#define __CPE_DEPTH_UNUSED(_v) ((_v) << __CPE_DEPTH_UNUSED_SH) +#define __CPE_MSIX_VEC_INDEX_MK 0x07ff0000 +#define __CPE_MSIX_VEC_INDEX_SH 16 +#define __CPE_MSIX_VEC_INDEX(_v) ((_v) << __CPE_MSIX_VEC_INDEX_SH) +#define __CPE_DEPTH 0x0000ffff +#define CPE_DEPTH_Q1 0x00038048 +#define CPE_QCTRL_Q0 0x0003800c +#define __CPE_CTRL_UNUSED30_MK 0xfc000000 +#define __CPE_CTRL_UNUSED30_SH 26 +#define __CPE_CTRL_UNUSED30(_v) ((_v) << __CPE_CTRL_UNUSED30_SH) +#define __CPE_FUNC_INT_CTRL_MK 0x03000000 +#define __CPE_FUNC_INT_CTRL_SH 24 +#define __CPE_FUNC_INT_CTRL(_v) ((_v) << __CPE_FUNC_INT_CTRL_SH) +enum { + __CPE_FUNC_INT_CTRL_DISABLE = 0x0, + __CPE_FUNC_INT_CTRL_F2NF = 0x1, + __CPE_FUNC_INT_CTRL_3QUART = 0x2, + __CPE_FUNC_INT_CTRL_HALF = 0x3, +}; +#define __CPE_CTRL_UNUSED20_MK 0x00f00000 +#define __CPE_CTRL_UNUSED20_SH 20 +#define __CPE_CTRL_UNUSED20(_v) ((_v) << __CPE_CTRL_UNUSED20_SH) +#define __CPE_SCI_TH_MK 0x000f0000 +#define __CPE_SCI_TH_SH 16 +#define __CPE_SCI_TH(_v) ((_v) << __CPE_SCI_TH_SH) +#define __CPE_CTRL_UNUSED10_MK 0x0000c000 +#define __CPE_CTRL_UNUSED10_SH 14 +#define __CPE_CTRL_UNUSED10(_v) ((_v) << __CPE_CTRL_UNUSED10_SH) +#define __CPE_ACK_PENDING 0x00002000 +#define __CPE_CTRL_UNUSED40_MK 0x00001c00 +#define __CPE_CTRL_UNUSED40_SH 10 +#define __CPE_CTRL_UNUSED40(_v) ((_v) << __CPE_CTRL_UNUSED40_SH) +#define __CPE_PCIEID_MK 0x00000300 +#define __CPE_PCIEID_SH 8 +#define __CPE_PCIEID(_v) ((_v) << __CPE_PCIEID_SH) +#define __CPE_CTRL_UNUSED00_MK 0x000000fe +#define __CPE_CTRL_UNUSED00_SH 1 +#define __CPE_CTRL_UNUSED00(_v) ((_v) << __CPE_CTRL_UNUSED00_SH) +#define __CPE_ESIZE 0x00000001 +#define CPE_QCTRL_Q1 0x0003804c +#define __CPE_CTRL_UNUSED31_MK 0xfc000000 +#define __CPE_CTRL_UNUSED31_SH 26 +#define __CPE_CTRL_UNUSED31(_v) ((_v) << __CPE_CTRL_UNUSED31_SH) +#define __CPE_CTRL_UNUSED21_MK 0x00f00000 +#define __CPE_CTRL_UNUSED21_SH 20 +#define __CPE_CTRL_UNUSED21(_v) ((_v) << __CPE_CTRL_UNUSED21_SH) +#define __CPE_CTRL_UNUSED11_MK 0x0000c000 +#define __CPE_CTRL_UNUSED11_SH 14 +#define __CPE_CTRL_UNUSED11(_v) ((_v) << __CPE_CTRL_UNUSED11_SH) +#define __CPE_CTRL_UNUSED41_MK 0x00001c00 +#define __CPE_CTRL_UNUSED41_SH 10 +#define __CPE_CTRL_UNUSED41(_v) ((_v) << __CPE_CTRL_UNUSED41_SH) +#define __CPE_CTRL_UNUSED01_MK 0x000000fe +#define __CPE_CTRL_UNUSED01_SH 1 +#define __CPE_CTRL_UNUSED01(_v) ((_v) << __CPE_CTRL_UNUSED01_SH) +#define RME_PI_PTR_Q0 0x00038020 +#define __LATENCY_TIME_STAMP_MK 0xffff0000 +#define __LATENCY_TIME_STAMP_SH 16 +#define __LATENCY_TIME_STAMP(_v) ((_v) << __LATENCY_TIME_STAMP_SH) +#define __RME_PI_PTR 0x0000ffff +#define RME_PI_PTR_Q1 0x00038060 +#define RME_CI_PTR_Q0 0x00038024 +#define __DELAY_TIME_STAMP_MK 0xffff0000 +#define __DELAY_TIME_STAMP_SH 16 +#define __DELAY_TIME_STAMP(_v) ((_v) << __DELAY_TIME_STAMP_SH) +#define __RME_CI_PTR 0x0000ffff +#define RME_CI_PTR_Q1 0x00038064 +#define RME_DEPTH_Q0 0x00038028 +#define __RME_DEPTH_UNUSED_MK 0xf8000000 +#define __RME_DEPTH_UNUSED_SH 27 +#define __RME_DEPTH_UNUSED(_v) ((_v) << __RME_DEPTH_UNUSED_SH) +#define __RME_MSIX_VEC_INDEX_MK 0x07ff0000 +#define __RME_MSIX_VEC_INDEX_SH 16 +#define __RME_MSIX_VEC_INDEX(_v) ((_v) << __RME_MSIX_VEC_INDEX_SH) +#define __RME_DEPTH 0x0000ffff +#define RME_DEPTH_Q1 0x00038068 +#define RME_QCTRL_Q0 0x0003802c +#define __RME_INT_LATENCY_TIMER_MK 0xff000000 +#define __RME_INT_LATENCY_TIMER_SH 24 +#define __RME_INT_LATENCY_TIMER(_v) ((_v) << __RME_INT_LATENCY_TIMER_SH) +#define __RME_INT_DELAY_TIMER_MK 0x00ff0000 +#define __RME_INT_DELAY_TIMER_SH 16 +#define __RME_INT_DELAY_TIMER(_v) ((_v) << __RME_INT_DELAY_TIMER_SH) +#define __RME_INT_DELAY_DISABLE 0x00008000 +#define __RME_DLY_DELAY_DISABLE 0x00004000 +#define __RME_ACK_PENDING 0x00002000 +#define __RME_FULL_INTERRUPT_DISABLE 0x00001000 +#define __RME_CTRL_UNUSED10_MK 0x00000c00 +#define __RME_CTRL_UNUSED10_SH 10 +#define __RME_CTRL_UNUSED10(_v) ((_v) << __RME_CTRL_UNUSED10_SH) +#define __RME_PCIEID_MK 0x00000300 +#define __RME_PCIEID_SH 8 +#define __RME_PCIEID(_v) ((_v) << __RME_PCIEID_SH) +#define __RME_CTRL_UNUSED00_MK 0x000000fe +#define __RME_CTRL_UNUSED00_SH 1 +#define __RME_CTRL_UNUSED00(_v) ((_v) << __RME_CTRL_UNUSED00_SH) +#define __RME_ESIZE 0x00000001 +#define RME_QCTRL_Q1 0x0003806c +#define __RME_CTRL_UNUSED11_MK 0x00000c00 +#define __RME_CTRL_UNUSED11_SH 10 +#define __RME_CTRL_UNUSED11(_v) ((_v) << __RME_CTRL_UNUSED11_SH) +#define __RME_CTRL_UNUSED01_MK 0x000000fe +#define __RME_CTRL_UNUSED01_SH 1 +#define __RME_CTRL_UNUSED01(_v) ((_v) << __RME_CTRL_UNUSED01_SH) +#define PSS_CTL_REG 0x00018800 +#define __PSS_I2C_CLK_DIV_MK 0x007f0000 +#define __PSS_I2C_CLK_DIV_SH 16 +#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH) +#define __PSS_LMEM_INIT_DONE 0x00001000 +#define __PSS_LMEM_RESET 0x00000200 +#define __PSS_LMEM_INIT_EN 0x00000100 +#define __PSS_LPU1_RESET 0x00000002 +#define __PSS_LPU0_RESET 0x00000001 +#define PSS_ERR_STATUS_REG 0x00018810 +#define __PSS_LPU1_TCM_READ_ERR 0x00200000 +#define __PSS_LPU0_TCM_READ_ERR 0x00100000 +#define __PSS_LMEM5_CORR_ERR 0x00080000 +#define __PSS_LMEM4_CORR_ERR 0x00040000 +#define __PSS_LMEM3_CORR_ERR 0x00020000 +#define __PSS_LMEM2_CORR_ERR 0x00010000 +#define __PSS_LMEM1_CORR_ERR 0x00008000 +#define __PSS_LMEM0_CORR_ERR 0x00004000 +#define __PSS_LMEM5_UNCORR_ERR 0x00002000 +#define __PSS_LMEM4_UNCORR_ERR 0x00001000 +#define __PSS_LMEM3_UNCORR_ERR 0x00000800 +#define __PSS_LMEM2_UNCORR_ERR 0x00000400 +#define __PSS_LMEM1_UNCORR_ERR 0x00000200 +#define __PSS_LMEM0_UNCORR_ERR 0x00000100 +#define __PSS_BAL_PERR 0x00000080 +#define __PSS_DIP_IF_ERR 0x00000040 +#define __PSS_IOH_IF_ERR 0x00000020 +#define __PSS_TDS_IF_ERR 0x00000010 +#define __PSS_RDS_IF_ERR 0x00000008 +#define __PSS_SGM_IF_ERR 0x00000004 +#define __PSS_LPU1_RAM_ERR 0x00000002 +#define __PSS_LPU0_RAM_ERR 0x00000001 +#define ERR_SET_REG 0x00018818 +#define __PSS_ERR_STATUS_SET 0x003fffff +#define PMM_1T_RESET_REG_P0 0x0002381c +#define __PMM_1T_RESET_P 0x00000001 +#define PMM_1T_RESET_REG_P1 0x00023c1c +#define HQM_QSET0_RXQ_DRBL_P0 0x00038000 +#define __RXQ0_ADD_VECTORS_P 0x80000000 +#define __RXQ0_STOP_P 0x40000000 +#define __RXQ0_PRD_PTR_P 0x0000ffff +#define HQM_QSET1_RXQ_DRBL_P0 0x00038080 +#define __RXQ1_ADD_VECTORS_P 0x80000000 +#define __RXQ1_STOP_P 0x40000000 +#define __RXQ1_PRD_PTR_P 0x0000ffff +#define HQM_QSET0_RXQ_DRBL_P1 0x0003c000 +#define HQM_QSET1_RXQ_DRBL_P1 0x0003c080 +#define HQM_QSET0_TXQ_DRBL_P0 0x00038020 +#define __TXQ0_ADD_VECTORS_P 0x80000000 +#define __TXQ0_STOP_P 0x40000000 +#define __TXQ0_PRD_PTR_P 0x0000ffff +#define HQM_QSET1_TXQ_DRBL_P0 0x000380a0 +#define __TXQ1_ADD_VECTORS_P 0x80000000 +#define __TXQ1_STOP_P 0x40000000 +#define __TXQ1_PRD_PTR_P 0x0000ffff +#define HQM_QSET0_TXQ_DRBL_P1 0x0003c020 +#define HQM_QSET1_TXQ_DRBL_P1 0x0003c0a0 +#define HQM_QSET0_IB_DRBL_1_P0 0x00038040 +#define __IB1_0_ACK_P 0x80000000 +#define __IB1_0_DISABLE_P 0x40000000 +#define __IB1_0_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB1_0_COALESCING_CFG_P_SH 16 +#define __IB1_0_COALESCING_CFG_P(_v) ((_v) << __IB1_0_COALESCING_CFG_P_SH) +#define __IB1_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET1_IB_DRBL_1_P0 0x000380c0 +#define __IB1_1_ACK_P 0x80000000 +#define __IB1_1_DISABLE_P 0x40000000 +#define __IB1_1_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB1_1_COALESCING_CFG_P_SH 16 +#define __IB1_1_COALESCING_CFG_P(_v) ((_v) << __IB1_1_COALESCING_CFG_P_SH) +#define __IB1_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET0_IB_DRBL_1_P1 0x0003c040 +#define HQM_QSET1_IB_DRBL_1_P1 0x0003c0c0 +#define HQM_QSET0_IB_DRBL_2_P0 0x00038060 +#define __IB2_0_ACK_P 0x80000000 +#define __IB2_0_DISABLE_P 0x40000000 +#define __IB2_0_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB2_0_COALESCING_CFG_P_SH 16 +#define __IB2_0_COALESCING_CFG_P(_v) ((_v) << __IB2_0_COALESCING_CFG_P_SH) +#define __IB2_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET1_IB_DRBL_2_P0 0x000380e0 +#define __IB2_1_ACK_P 0x80000000 +#define __IB2_1_DISABLE_P 0x40000000 +#define __IB2_1_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB2_1_COALESCING_CFG_P_SH 16 +#define __IB2_1_COALESCING_CFG_P(_v) ((_v) << __IB2_1_COALESCING_CFG_P_SH) +#define __IB2_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET0_IB_DRBL_2_P1 0x0003c060 +#define HQM_QSET1_IB_DRBL_2_P1 0x0003c0e0 + + +/* + * These definitions are either in error/missing in spec. Its auto-generated + * from hard coded values in regparse.pl. + */ +#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c +#define __EMPHPOST_AT_4G_SH_FIX 0x00000002 +#define __EMPHPRE_AT_4G_FIX 0x00000003 +#define __SFP_TXRATE_EN_FIX 0x00000100 +#define __SFP_RXRATE_EN_FIX 0x00000080 + + +/* + * These register definitions are auto-generated from hard coded values + * in regparse.pl. + */ + + +/* + * These register mapping definitions are auto-generated from mapping tables + * in regparse.pl. + */ +#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG +#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG +#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG +#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG +#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG +#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG + +#define CPE_DEPTH_Q(__n) \ + (CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0)) +#define CPE_QCTRL_Q(__n) \ + (CPE_QCTRL_Q0 + (__n) * (CPE_QCTRL_Q1 - CPE_QCTRL_Q0)) +#define CPE_PI_PTR_Q(__n) \ + (CPE_PI_PTR_Q0 + (__n) * (CPE_PI_PTR_Q1 - CPE_PI_PTR_Q0)) +#define CPE_CI_PTR_Q(__n) \ + (CPE_CI_PTR_Q0 + (__n) * (CPE_CI_PTR_Q1 - CPE_CI_PTR_Q0)) +#define RME_DEPTH_Q(__n) \ + (RME_DEPTH_Q0 + (__n) * (RME_DEPTH_Q1 - RME_DEPTH_Q0)) +#define RME_QCTRL_Q(__n) \ + (RME_QCTRL_Q0 + (__n) * (RME_QCTRL_Q1 - RME_QCTRL_Q0)) +#define RME_PI_PTR_Q(__n) \ + (RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0)) +#define RME_CI_PTR_Q(__n) \ + (RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0)) +#define HQM_QSET_RXQ_DRBL_P0(__n) \ + (HQM_QSET0_RXQ_DRBL_P0 + (__n) * \ + (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0)) +#define HQM_QSET_TXQ_DRBL_P0(__n) \ + (HQM_QSET0_TXQ_DRBL_P0 + (__n) * \ + (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0)) +#define HQM_QSET_IB_DRBL_1_P0(__n) \ + (HQM_QSET0_IB_DRBL_1_P0 + (__n) * \ + (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0)) +#define HQM_QSET_IB_DRBL_2_P0(__n) \ + (HQM_QSET0_IB_DRBL_2_P0 + (__n) * \ + (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0)) +#define HQM_QSET_RXQ_DRBL_P1(__n) \ + (HQM_QSET0_RXQ_DRBL_P1 + (__n) * \ + (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1)) +#define HQM_QSET_TXQ_DRBL_P1(__n) \ + (HQM_QSET0_TXQ_DRBL_P1 + (__n) * \ + (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1)) +#define HQM_QSET_IB_DRBL_1_P1(__n) \ + (HQM_QSET0_IB_DRBL_1_P1 + (__n) * \ + (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1)) +#define HQM_QSET_IB_DRBL_2_P1(__n) \ + (HQM_QSET0_IB_DRBL_2_P1 + (__n) * \ + (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1)) + +#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) +#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) +#define CPE_Q_MASK(__q) ((__q) & 0x3) +#define RME_Q_MASK(__q) ((__q) & 0x3) + + +/* + * PCI MSI-X vector defines + */ +enum { + BFA_MSIX_CPE_Q0 = 0, + BFA_MSIX_CPE_Q1 = 1, + BFA_MSIX_CPE_Q2 = 2, + BFA_MSIX_CPE_Q3 = 3, + BFA_MSIX_RME_Q0 = 4, + BFA_MSIX_RME_Q1 = 5, + BFA_MSIX_RME_Q2 = 6, + BFA_MSIX_RME_Q3 = 7, + BFA_MSIX_LPU_ERR = 8, + BFA_MSIX_CT_MAX = 9, +}; + +/* + * And corresponding host interrupt status bit field defines + */ +#define __HFN_INT_CPE_Q0 0x00000001U +#define __HFN_INT_CPE_Q1 0x00000002U +#define __HFN_INT_CPE_Q2 0x00000004U +#define __HFN_INT_CPE_Q3 0x00000008U +#define __HFN_INT_CPE_Q4 0x00000010U +#define __HFN_INT_CPE_Q5 0x00000020U +#define __HFN_INT_CPE_Q6 0x00000040U +#define __HFN_INT_CPE_Q7 0x00000080U +#define __HFN_INT_RME_Q0 0x00000100U +#define __HFN_INT_RME_Q1 0x00000200U +#define __HFN_INT_RME_Q2 0x00000400U +#define __HFN_INT_RME_Q3 0x00000800U +#define __HFN_INT_RME_Q4 0x00001000U +#define __HFN_INT_RME_Q5 0x00002000U +#define __HFN_INT_RME_Q6 0x00004000U +#define __HFN_INT_RME_Q7 0x00008000U +#define __HFN_INT_ERR_EMC 0x00010000U +#define __HFN_INT_ERR_LPU0 0x00020000U +#define __HFN_INT_ERR_LPU1 0x00040000U +#define __HFN_INT_ERR_PSS 0x00080000U +#define __HFN_INT_MBOX_LPU0 0x00100000U +#define __HFN_INT_MBOX_LPU1 0x00200000U +#define __HFN_INT_MBOX1_LPU0 0x00400000U +#define __HFN_INT_MBOX1_LPU1 0x00800000U +#define __HFN_INT_LL_HALT 0x01000000U +#define __HFN_INT_CPE_MASK 0x000000ffU +#define __HFN_INT_RME_MASK 0x0000ff00U + + +/* + * catapult memory map. + */ +#define LL_PGN_HQM0 0x0096 +#define LL_PGN_HQM1 0x0097 +#define PSS_SMEM_PAGE_START 0x8000 +#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15)) +#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff) + +/* + * End of catapult memory map + */ + + +#endif /* __BFI_CTREG_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfi_ms.h b/trunk/drivers/scsi/bfa/bfi_ms.h index 0d9f1fb50db0..19e888a57555 100644 --- a/trunk/drivers/scsi/bfa/bfi_ms.h +++ b/trunk/drivers/scsi/bfa/bfi_ms.h @@ -28,17 +28,11 @@ enum bfi_iocfc_h2i_msgs { BFI_IOCFC_H2I_CFG_REQ = 1, BFI_IOCFC_H2I_SET_INTR_REQ = 2, BFI_IOCFC_H2I_UPDATEQ_REQ = 3, - BFI_IOCFC_H2I_FAA_ENABLE_REQ = 4, - BFI_IOCFC_H2I_FAA_DISABLE_REQ = 5, - BFI_IOCFC_H2I_FAA_QUERY_REQ = 6, }; enum bfi_iocfc_i2h_msgs { BFI_IOCFC_I2H_CFG_REPLY = BFA_I2HM(1), BFI_IOCFC_I2H_UPDATEQ_RSP = BFA_I2HM(3), - BFI_IOCFC_I2H_FAA_ENABLE_RSP = BFA_I2HM(4), - BFI_IOCFC_I2H_FAA_DISABLE_RSP = BFA_I2HM(5), - BFI_IOCFC_I2H_FAA_QUERY_RSP = BFA_I2HM(6), }; struct bfi_iocfc_cfg_s { @@ -46,12 +40,6 @@ struct bfi_iocfc_cfg_s { u8 sense_buf_len; /* SCSI sense length */ u16 rsvd_1; u32 endian_sig; /* endian signature of host */ - u8 rsvd_2; - u8 single_msix_vec; - u8 rsvd[2]; - __be16 num_ioim_reqs; - __be16 num_fwtio_reqs; - /* * Request and response circular queue base addresses, size and @@ -66,8 +54,7 @@ struct bfi_iocfc_cfg_s { union bfi_addr_u stats_addr; /* DMA-able address for stats */ union bfi_addr_u cfgrsp_addr; /* config response dma address */ - union bfi_addr_u ioim_snsbase[BFI_IOIM_SNSBUF_SEGS]; - /* IO sense buf base addr segments */ + union bfi_addr_u ioim_snsbase; /* IO sense buffer base address */ struct bfa_iocfc_intr_attr_s intr_attr; /* IOC interrupt attributes */ }; @@ -81,25 +68,11 @@ struct bfi_iocfc_bootwwns { u8 rsvd[7]; }; -/** - * Queue configuration response from firmware - */ -struct bfi_iocfc_qreg_s { - u32 cpe_q_ci_off[BFI_IOC_MAX_CQS]; - u32 cpe_q_pi_off[BFI_IOC_MAX_CQS]; - u32 cpe_qctl_off[BFI_IOC_MAX_CQS]; - u32 rme_q_ci_off[BFI_IOC_MAX_CQS]; - u32 rme_q_pi_off[BFI_IOC_MAX_CQS]; - u32 rme_qctl_off[BFI_IOC_MAX_CQS]; - u8 hw_qid[BFI_IOC_MAX_CQS]; -}; - struct bfi_iocfc_cfgrsp_s { struct bfa_iocfc_fwcfg_s fwcfg; struct bfa_iocfc_intr_attr_s intr_attr; struct bfi_iocfc_bootwwns bootwwns; struct bfi_pbc_s pbc_cfg; - struct bfi_iocfc_qreg_s qreg; }; /* @@ -177,37 +150,6 @@ union bfi_iocfc_i2h_msg_u { u32 mboxmsg[BFI_IOC_MSGSZ]; }; -/* - * BFI_IOCFC_H2I_FAA_ENABLE_REQ BFI_IOCFC_H2I_FAA_DISABLE_REQ message - */ -struct bfi_faa_en_dis_s { - struct bfi_mhdr_s mh; /* common msg header */ -}; - -/* - * BFI_IOCFC_H2I_FAA_QUERY_REQ message - */ -struct bfi_faa_query_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 faa_status; /* FAA status */ - u8 addr_source; /* PWWN source */ - u8 rsvd[2]; - wwn_t faa; /* Fabric acquired PWWN */ -}; - -/* - * BFI_IOCFC_I2H_FAA_ENABLE_RSP, BFI_IOCFC_I2H_FAA_DISABLE_RSP message - */ -struct bfi_faa_en_dis_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* updateq status */ - u8 rsvd[3]; -}; - -/* - * BFI_IOCFC_I2H_FAA_QUERY_RSP message - */ -#define bfi_faa_query_rsp_t struct bfi_faa_query_s enum bfi_fcport_h2i { BFI_FCPORT_H2I_ENABLE_REQ = (1), @@ -271,8 +213,7 @@ struct bfi_fcport_enable_req_s { struct bfi_fcport_set_svc_params_req_s { struct bfi_mhdr_s mh; /* msg header */ __be16 tx_bbcredit; /* Tx credits */ - u8 bb_scn; /* BB_SC FC credit recovery */ - u8 rsvd; + u16 rsvd; }; /* @@ -352,12 +293,12 @@ struct bfi_fcxp_send_req_s { u8 class; /* FC class used for req/rsp */ u8 rsp_timeout; /* timeout in secs, 0-no response */ u8 cts; /* continue sequence */ - u8 lp_fwtag; /* lport tag */ + u8 lp_tag; /* lport tag */ struct fchs_s fchs; /* request FC header structure */ __be32 req_len; /* request payload length */ __be32 rsp_maxlen; /* max response length expected */ - struct bfi_alen_s req_alen; /* request buffer */ - struct bfi_alen_s rsp_alen; /* response buffer */ + struct bfi_sge_s req_sge[BFA_FCXP_MAX_SGES]; /* request buf */ + struct bfi_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; /* response buf */ }; /* @@ -387,7 +328,7 @@ struct bfi_uf_buf_post_s { struct bfi_mhdr_s mh; /* Common msg header */ u16 buf_tag; /* buffer tag */ __be16 buf_len; /* total buffer length */ - struct bfi_alen_s alen; /* buffer address/len pair */ + struct bfi_sge_s sge[BFA_UF_MAX_SGES]; /* buffer DMA SGEs */ }; struct bfi_uf_frm_rcvd_s { @@ -405,27 +346,26 @@ enum bfi_lps_h2i_msgs { }; enum bfi_lps_i2h_msgs { - BFI_LPS_I2H_LOGIN_RSP = BFA_I2HM(1), - BFI_LPS_I2H_LOGOUT_RSP = BFA_I2HM(2), - BFI_LPS_I2H_CVL_EVENT = BFA_I2HM(3), + BFI_LPS_H2I_LOGIN_RSP = BFA_I2HM(1), + BFI_LPS_H2I_LOGOUT_RSP = BFA_I2HM(2), + BFI_LPS_H2I_CVL_EVENT = BFA_I2HM(3), }; struct bfi_lps_login_req_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 bfa_tag; + u8 lp_tag; u8 alpa; __be16 pdu_size; wwn_t pwwn; wwn_t nwwn; u8 fdisc; u8 auth_en; - u8 lps_role; - u8 bb_scn; + u8 rsvd[2]; }; struct bfi_lps_login_rsp_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 fw_tag; + u8 lp_tag; u8 status; u8 lsrjt_rsn; u8 lsrjt_expl; @@ -440,33 +380,31 @@ struct bfi_lps_login_rsp_s { mac_t fcf_mac; u8 ext_status; u8 brcd_switch; /* attached peer is brcd switch */ - u8 bb_scn; /* atatched port's bb_scn */ - u8 bfa_tag; }; struct bfi_lps_logout_req_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 fw_tag; + u8 lp_tag; u8 rsvd[3]; wwn_t port_name; }; struct bfi_lps_logout_rsp_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 bfa_tag; + u8 lp_tag; u8 status; u8 rsvd[2]; }; struct bfi_lps_cvl_event_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 bfa_tag; + u8 lp_tag; u8 rsvd[3]; }; struct bfi_lps_n2n_pid_req_s { struct bfi_mhdr_s mh; /* common msg header */ - u8 fw_tag; + u8 lp_tag; u32 lp_pid:24; }; @@ -501,7 +439,7 @@ struct bfi_rport_create_req_s { u16 bfa_handle; /* host rport handle */ __be16 max_frmsz; /* max rcv pdu size */ u32 pid:24, /* remote port ID */ - lp_fwtag:8; /* local port tag */ + lp_tag:8; /* local port tag */ u32 local_pid:24, /* local port ID */ cisc:8; u8 fc_class; /* supported FC classes */ @@ -564,63 +502,62 @@ union bfi_rport_i2h_msg_u { * Initiator mode I-T nexus interface defines. */ -enum bfi_itn_h2i { - BFI_ITN_H2I_CREATE_REQ = 1, /* i-t nexus creation */ - BFI_ITN_H2I_DELETE_REQ = 2, /* i-t nexus deletion */ +enum bfi_itnim_h2i { + BFI_ITNIM_H2I_CREATE_REQ = 1, /* i-t nexus creation */ + BFI_ITNIM_H2I_DELETE_REQ = 2, /* i-t nexus deletion */ }; -enum bfi_itn_i2h { - BFI_ITN_I2H_CREATE_RSP = BFA_I2HM(1), - BFI_ITN_I2H_DELETE_RSP = BFA_I2HM(2), - BFI_ITN_I2H_SLER_EVENT = BFA_I2HM(3), +enum bfi_itnim_i2h { + BFI_ITNIM_I2H_CREATE_RSP = BFA_I2HM(1), + BFI_ITNIM_I2H_DELETE_RSP = BFA_I2HM(2), + BFI_ITNIM_I2H_SLER_EVENT = BFA_I2HM(3), }; -struct bfi_itn_create_req_s { +struct bfi_itnim_create_req_s { struct bfi_mhdr_s mh; /* common msg header */ u16 fw_handle; /* f/w handle for itnim */ u8 class; /* FC class for IO */ u8 seq_rec; /* sequence recovery support */ u8 msg_no; /* seq id of the msg */ - u8 role; }; -struct bfi_itn_create_rsp_s { +struct bfi_itnim_create_rsp_s { struct bfi_mhdr_s mh; /* common msg header */ u16 bfa_handle; /* bfa handle for itnim */ u8 status; /* fcp request status */ u8 seq_id; /* seq id of the msg */ }; -struct bfi_itn_delete_req_s { +struct bfi_itnim_delete_req_s { struct bfi_mhdr_s mh; /* common msg header */ u16 fw_handle; /* f/w itnim handle */ u8 seq_id; /* seq id of the msg */ u8 rsvd; }; -struct bfi_itn_delete_rsp_s { +struct bfi_itnim_delete_rsp_s { struct bfi_mhdr_s mh; /* common msg header */ u16 bfa_handle; /* bfa handle for itnim */ u8 status; /* fcp request status */ u8 seq_id; /* seq id of the msg */ }; -struct bfi_itn_sler_event_s { +struct bfi_itnim_sler_event_s { struct bfi_mhdr_s mh; /* common msg header */ u16 bfa_handle; /* bfa handle for itnim */ u16 rsvd; }; -union bfi_itn_h2i_msg_u { - struct bfi_itn_create_req_s *create_req; - struct bfi_itn_delete_req_s *delete_req; +union bfi_itnim_h2i_msg_u { + struct bfi_itnim_create_req_s *create_req; + struct bfi_itnim_delete_req_s *delete_req; struct bfi_msg_s *msg; }; -union bfi_itn_i2h_msg_u { - struct bfi_itn_create_rsp_s *create_rsp; - struct bfi_itn_delete_rsp_s *delete_rsp; - struct bfi_itn_sler_event_s *sler_event; +union bfi_itnim_i2h_msg_u { + struct bfi_itnim_create_rsp_s *create_rsp; + struct bfi_itnim_delete_rsp_s *delete_rsp; + struct bfi_itnim_sler_event_s *sler_event; struct bfi_msg_s *msg; }; @@ -756,6 +693,7 @@ enum bfi_ioim_status { BFI_IOIM_STS_PATHTOV = 8, }; +#define BFI_IOIM_SNSLEN (256) /* * I/O response message */ @@ -834,27 +772,4 @@ struct bfi_tskim_rsp_s { #pragma pack() -/* - * Crossbow PCI MSI-X vector defines - */ -enum { - BFI_MSIX_CPE_QMIN_CB = 0, - BFI_MSIX_CPE_QMAX_CB = 7, - BFI_MSIX_RME_QMIN_CB = 8, - BFI_MSIX_RME_QMAX_CB = 15, - BFI_MSIX_CB_MAX = 22, -}; - -/* - * Catapult FC PCI MSI-X vector defines - */ -enum { - BFI_MSIX_LPU_ERR_CT = 0, - BFI_MSIX_CPE_QMIN_CT = 1, - BFI_MSIX_CPE_QMAX_CT = 4, - BFI_MSIX_RME_QMIN_CT = 5, - BFI_MSIX_RME_QMAX_CT = 8, - BFI_MSIX_CT_MAX = 9, -}; - #endif /* __BFI_MS_H__ */ diff --git a/trunk/drivers/scsi/bfa/bfi_reg.h b/trunk/drivers/scsi/bfa/bfi_reg.h deleted file mode 100644 index d892064b64a8..000000000000 --- a/trunk/drivers/scsi/bfa/bfi_reg.h +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) 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. - */ - -/* - * bfi_reg.h ASIC register defines for all Brocade adapter ASICs - */ - -#ifndef __BFI_REG_H__ -#define __BFI_REG_H__ - -#define HOSTFN0_INT_STATUS 0x00014000 /* cb/ct */ -#define HOSTFN1_INT_STATUS 0x00014100 /* cb/ct */ -#define HOSTFN2_INT_STATUS 0x00014300 /* ct */ -#define HOSTFN3_INT_STATUS 0x00014400 /* ct */ -#define HOSTFN0_INT_MSK 0x00014004 /* cb/ct */ -#define HOSTFN1_INT_MSK 0x00014104 /* cb/ct */ -#define HOSTFN2_INT_MSK 0x00014304 /* ct */ -#define HOSTFN3_INT_MSK 0x00014404 /* ct */ - -#define HOST_PAGE_NUM_FN0 0x00014008 /* cb/ct */ -#define HOST_PAGE_NUM_FN1 0x00014108 /* cb/ct */ -#define HOST_PAGE_NUM_FN2 0x00014308 /* ct */ -#define HOST_PAGE_NUM_FN3 0x00014408 /* ct */ - -#define APP_PLL_LCLK_CTL_REG 0x00014204 /* cb/ct */ -#define __P_LCLK_PLL_LOCK 0x80000000 -#define __APP_PLL_LCLK_SRAM_USE_100MHZ 0x00100000 -#define __APP_PLL_LCLK_RESET_TIMER_MK 0x000e0000 -#define __APP_PLL_LCLK_RESET_TIMER_SH 17 -#define __APP_PLL_LCLK_RESET_TIMER(_v) ((_v) << __APP_PLL_LCLK_RESET_TIMER_SH) -#define __APP_PLL_LCLK_LOGIC_SOFT_RESET 0x00010000 -#define __APP_PLL_LCLK_CNTLMT0_1_MK 0x0000c000 -#define __APP_PLL_LCLK_CNTLMT0_1_SH 14 -#define __APP_PLL_LCLK_CNTLMT0_1(_v) ((_v) << __APP_PLL_LCLK_CNTLMT0_1_SH) -#define __APP_PLL_LCLK_JITLMT0_1_MK 0x00003000 -#define __APP_PLL_LCLK_JITLMT0_1_SH 12 -#define __APP_PLL_LCLK_JITLMT0_1(_v) ((_v) << __APP_PLL_LCLK_JITLMT0_1_SH) -#define __APP_PLL_LCLK_HREF 0x00000800 -#define __APP_PLL_LCLK_HDIV 0x00000400 -#define __APP_PLL_LCLK_P0_1_MK 0x00000300 -#define __APP_PLL_LCLK_P0_1_SH 8 -#define __APP_PLL_LCLK_P0_1(_v) ((_v) << __APP_PLL_LCLK_P0_1_SH) -#define __APP_PLL_LCLK_Z0_2_MK 0x000000e0 -#define __APP_PLL_LCLK_Z0_2_SH 5 -#define __APP_PLL_LCLK_Z0_2(_v) ((_v) << __APP_PLL_LCLK_Z0_2_SH) -#define __APP_PLL_LCLK_RSEL200500 0x00000010 -#define __APP_PLL_LCLK_ENARST 0x00000008 -#define __APP_PLL_LCLK_BYPASS 0x00000004 -#define __APP_PLL_LCLK_LRESETN 0x00000002 -#define __APP_PLL_LCLK_ENABLE 0x00000001 -#define APP_PLL_SCLK_CTL_REG 0x00014208 /* cb/ct */ -#define __P_SCLK_PLL_LOCK 0x80000000 -#define __APP_PLL_SCLK_RESET_TIMER_MK 0x000e0000 -#define __APP_PLL_SCLK_RESET_TIMER_SH 17 -#define __APP_PLL_SCLK_RESET_TIMER(_v) ((_v) << __APP_PLL_SCLK_RESET_TIMER_SH) -#define __APP_PLL_SCLK_LOGIC_SOFT_RESET 0x00010000 -#define __APP_PLL_SCLK_CNTLMT0_1_MK 0x0000c000 -#define __APP_PLL_SCLK_CNTLMT0_1_SH 14 -#define __APP_PLL_SCLK_CNTLMT0_1(_v) ((_v) << __APP_PLL_SCLK_CNTLMT0_1_SH) -#define __APP_PLL_SCLK_JITLMT0_1_MK 0x00003000 -#define __APP_PLL_SCLK_JITLMT0_1_SH 12 -#define __APP_PLL_SCLK_JITLMT0_1(_v) ((_v) << __APP_PLL_SCLK_JITLMT0_1_SH) -#define __APP_PLL_SCLK_HREF 0x00000800 -#define __APP_PLL_SCLK_HDIV 0x00000400 -#define __APP_PLL_SCLK_P0_1_MK 0x00000300 -#define __APP_PLL_SCLK_P0_1_SH 8 -#define __APP_PLL_SCLK_P0_1(_v) ((_v) << __APP_PLL_SCLK_P0_1_SH) -#define __APP_PLL_SCLK_Z0_2_MK 0x000000e0 -#define __APP_PLL_SCLK_Z0_2_SH 5 -#define __APP_PLL_SCLK_Z0_2(_v) ((_v) << __APP_PLL_SCLK_Z0_2_SH) -#define __APP_PLL_SCLK_RSEL200500 0x00000010 -#define __APP_PLL_SCLK_ENARST 0x00000008 -#define __APP_PLL_SCLK_BYPASS 0x00000004 -#define __APP_PLL_SCLK_LRESETN 0x00000002 -#define __APP_PLL_SCLK_ENABLE 0x00000001 -#define __ENABLE_MAC_AHB_1 0x00800000 /* ct */ -#define __ENABLE_MAC_AHB_0 0x00400000 /* ct */ -#define __ENABLE_MAC_1 0x00200000 /* ct */ -#define __ENABLE_MAC_0 0x00100000 /* ct */ - -#define HOST_SEM0_REG 0x00014230 /* cb/ct */ -#define HOST_SEM1_REG 0x00014234 /* cb/ct */ -#define HOST_SEM2_REG 0x00014238 /* cb/ct */ -#define HOST_SEM3_REG 0x0001423c /* cb/ct */ -#define HOST_SEM4_REG 0x00014610 /* cb/ct */ -#define HOST_SEM5_REG 0x00014614 /* cb/ct */ -#define HOST_SEM6_REG 0x00014618 /* cb/ct */ -#define HOST_SEM7_REG 0x0001461c /* cb/ct */ -#define HOST_SEM0_INFO_REG 0x00014240 /* cb/ct */ -#define HOST_SEM1_INFO_REG 0x00014244 /* cb/ct */ -#define HOST_SEM2_INFO_REG 0x00014248 /* cb/ct */ -#define HOST_SEM3_INFO_REG 0x0001424c /* cb/ct */ -#define HOST_SEM4_INFO_REG 0x00014620 /* cb/ct */ -#define HOST_SEM5_INFO_REG 0x00014624 /* cb/ct */ -#define HOST_SEM6_INFO_REG 0x00014628 /* cb/ct */ -#define HOST_SEM7_INFO_REG 0x0001462c /* cb/ct */ - -#define HOSTFN0_LPU0_CMD_STAT 0x00019000 /* cb/ct */ -#define HOSTFN0_LPU1_CMD_STAT 0x00019004 /* cb/ct */ -#define HOSTFN1_LPU0_CMD_STAT 0x00019010 /* cb/ct */ -#define HOSTFN1_LPU1_CMD_STAT 0x00019014 /* cb/ct */ -#define HOSTFN2_LPU0_CMD_STAT 0x00019150 /* ct */ -#define HOSTFN2_LPU1_CMD_STAT 0x00019154 /* ct */ -#define HOSTFN3_LPU0_CMD_STAT 0x00019160 /* ct */ -#define HOSTFN3_LPU1_CMD_STAT 0x00019164 /* ct */ -#define LPU0_HOSTFN0_CMD_STAT 0x00019008 /* cb/ct */ -#define LPU1_HOSTFN0_CMD_STAT 0x0001900c /* cb/ct */ -#define LPU0_HOSTFN1_CMD_STAT 0x00019018 /* cb/ct */ -#define LPU1_HOSTFN1_CMD_STAT 0x0001901c /* cb/ct */ -#define LPU0_HOSTFN2_CMD_STAT 0x00019158 /* ct */ -#define LPU1_HOSTFN2_CMD_STAT 0x0001915c /* ct */ -#define LPU0_HOSTFN3_CMD_STAT 0x00019168 /* ct */ -#define LPU1_HOSTFN3_CMD_STAT 0x0001916c /* ct */ - -#define PSS_CTL_REG 0x00018800 /* cb/ct */ -#define __PSS_I2C_CLK_DIV_MK 0x007f0000 -#define __PSS_I2C_CLK_DIV_SH 16 -#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH) -#define __PSS_LMEM_INIT_DONE 0x00001000 -#define __PSS_LMEM_RESET 0x00000200 -#define __PSS_LMEM_INIT_EN 0x00000100 -#define __PSS_LPU1_RESET 0x00000002 -#define __PSS_LPU0_RESET 0x00000001 -#define PSS_ERR_STATUS_REG 0x00018810 /* cb/ct */ -#define ERR_SET_REG 0x00018818 /* cb/ct */ -#define PSS_GPIO_OUT_REG 0x000188c0 /* cb/ct */ -#define __PSS_GPIO_OUT_REG 0x00000fff -#define PSS_GPIO_OE_REG 0x000188c8 /* cb/ct */ -#define __PSS_GPIO_OE_REG 0x000000ff - -#define HOSTFN0_LPU_MBOX0_0 0x00019200 /* cb/ct */ -#define HOSTFN1_LPU_MBOX0_8 0x00019260 /* cb/ct */ -#define LPU_HOSTFN0_MBOX0_0 0x00019280 /* cb/ct */ -#define LPU_HOSTFN1_MBOX0_8 0x000192e0 /* cb/ct */ -#define HOSTFN2_LPU_MBOX0_0 0x00019400 /* ct */ -#define HOSTFN3_LPU_MBOX0_8 0x00019460 /* ct */ -#define LPU_HOSTFN2_MBOX0_0 0x00019480 /* ct */ -#define LPU_HOSTFN3_MBOX0_8 0x000194e0 /* ct */ - -#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c /* ct */ -#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c /* ct */ -#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c /* ct */ -#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c /* ct */ - -#define MBIST_CTL_REG 0x00014220 /* ct */ -#define __EDRAM_BISTR_START 0x00000004 -#define MBIST_STAT_REG 0x00014224 /* ct */ -#define ETH_MAC_SER_REG 0x00014288 /* ct */ -#define __APP_EMS_CKBUFAMPIN 0x00000020 -#define __APP_EMS_REFCLKSEL 0x00000010 -#define __APP_EMS_CMLCKSEL 0x00000008 -#define __APP_EMS_REFCKBUFEN2 0x00000004 -#define __APP_EMS_REFCKBUFEN1 0x00000002 -#define __APP_EMS_CHANNEL_SEL 0x00000001 -#define FNC_PERS_REG 0x00014604 /* ct */ -#define __F3_FUNCTION_ACTIVE 0x80000000 -#define __F3_FUNCTION_MODE 0x40000000 -#define __F3_PORT_MAP_MK 0x30000000 -#define __F3_PORT_MAP_SH 28 -#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH) -#define __F3_VM_MODE 0x08000000 -#define __F3_INTX_STATUS_MK 0x07000000 -#define __F3_INTX_STATUS_SH 24 -#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH) -#define __F2_FUNCTION_ACTIVE 0x00800000 -#define __F2_FUNCTION_MODE 0x00400000 -#define __F2_PORT_MAP_MK 0x00300000 -#define __F2_PORT_MAP_SH 20 -#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH) -#define __F2_VM_MODE 0x00080000 -#define __F2_INTX_STATUS_MK 0x00070000 -#define __F2_INTX_STATUS_SH 16 -#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH) -#define __F1_FUNCTION_ACTIVE 0x00008000 -#define __F1_FUNCTION_MODE 0x00004000 -#define __F1_PORT_MAP_MK 0x00003000 -#define __F1_PORT_MAP_SH 12 -#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH) -#define __F1_VM_MODE 0x00000800 -#define __F1_INTX_STATUS_MK 0x00000700 -#define __F1_INTX_STATUS_SH 8 -#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH) -#define __F0_FUNCTION_ACTIVE 0x00000080 -#define __F0_FUNCTION_MODE 0x00000040 -#define __F0_PORT_MAP_MK 0x00000030 -#define __F0_PORT_MAP_SH 4 -#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH) -#define __F0_VM_MODE 0x00000008 -#define __F0_INTX_STATUS 0x00000007 -enum { - __F0_INTX_STATUS_MSIX = 0x0, - __F0_INTX_STATUS_INTA = 0x1, - __F0_INTX_STATUS_INTB = 0x2, - __F0_INTX_STATUS_INTC = 0x3, - __F0_INTX_STATUS_INTD = 0x4, -}; - -#define OP_MODE 0x0001460c /* ct */ -#define __APP_ETH_CLK_LOWSPEED 0x00000004 -#define __GLOBAL_CORECLK_HALFSPEED 0x00000002 -#define __GLOBAL_FCOE_MODE 0x00000001 -#define FW_INIT_HALT_P0 0x000191ac /* ct */ -#define __FW_INIT_HALT_P 0x00000001 -#define FW_INIT_HALT_P1 0x000191bc /* ct */ -#define PMM_1T_RESET_REG_P0 0x0002381c /* ct */ -#define __PMM_1T_RESET_P 0x00000001 -#define PMM_1T_RESET_REG_P1 0x00023c1c /* ct */ - -/** - * Catapult-2 specific defines - */ -#define CT2_PCI_CPQ_BASE 0x00030000 -#define CT2_PCI_APP_BASE 0x00030100 -#define CT2_PCI_ETH_BASE 0x00030400 - -/* - * APP block registers - */ -#define CT2_HOSTFN_INT_STATUS (CT2_PCI_APP_BASE + 0x00) -#define CT2_HOSTFN_INTR_MASK (CT2_PCI_APP_BASE + 0x04) -#define CT2_HOSTFN_PERSONALITY0 (CT2_PCI_APP_BASE + 0x08) -#define __PME_STATUS_ 0x00200000 -#define __PF_VF_BAR_SIZE_MODE__MK 0x00180000 -#define __PF_VF_BAR_SIZE_MODE__SH 19 -#define __PF_VF_BAR_SIZE_MODE_(_v) ((_v) << __PF_VF_BAR_SIZE_MODE__SH) -#define __FC_LL_PORT_MAP__MK 0x00060000 -#define __FC_LL_PORT_MAP__SH 17 -#define __FC_LL_PORT_MAP_(_v) ((_v) << __FC_LL_PORT_MAP__SH) -#define __PF_VF_ACTIVE_ 0x00010000 -#define __PF_VF_CFG_RDY_ 0x00008000 -#define __PF_VF_ENABLE_ 0x00004000 -#define __PF_DRIVER_ACTIVE_ 0x00002000 -#define __PF_PME_SEND_ENABLE_ 0x00001000 -#define __PF_EXROM_OFFSET__MK 0x00000ff0 -#define __PF_EXROM_OFFSET__SH 4 -#define __PF_EXROM_OFFSET_(_v) ((_v) << __PF_EXROM_OFFSET__SH) -#define __FC_LL_MODE_ 0x00000008 -#define __PF_INTX_PIN_ 0x00000007 -#define CT2_HOSTFN_PERSONALITY1 (CT2_PCI_APP_BASE + 0x0C) -#define __PF_NUM_QUEUES1__MK 0xff000000 -#define __PF_NUM_QUEUES1__SH 24 -#define __PF_NUM_QUEUES1_(_v) ((_v) << __PF_NUM_QUEUES1__SH) -#define __PF_VF_QUE_OFFSET1__MK 0x00ff0000 -#define __PF_VF_QUE_OFFSET1__SH 16 -#define __PF_VF_QUE_OFFSET1_(_v) ((_v) << __PF_VF_QUE_OFFSET1__SH) -#define __PF_VF_NUM_QUEUES__MK 0x0000ff00 -#define __PF_VF_NUM_QUEUES__SH 8 -#define __PF_VF_NUM_QUEUES_(_v) ((_v) << __PF_VF_NUM_QUEUES__SH) -#define __PF_VF_QUE_OFFSET_ 0x000000ff -#define CT2_HOSTFN_PAGE_NUM (CT2_PCI_APP_BASE + 0x18) -#define CT2_HOSTFN_MSIX_VT_INDEX_MBOX_ERR (CT2_PCI_APP_BASE + 0x38) - -/* - * Catapult-2 CPQ block registers - */ -#define CT2_HOSTFN_LPU0_MBOX0 (CT2_PCI_CPQ_BASE + 0x00) -#define CT2_HOSTFN_LPU1_MBOX0 (CT2_PCI_CPQ_BASE + 0x20) -#define CT2_LPU0_HOSTFN_MBOX0 (CT2_PCI_CPQ_BASE + 0x40) -#define CT2_LPU1_HOSTFN_MBOX0 (CT2_PCI_CPQ_BASE + 0x60) -#define CT2_HOSTFN_LPU0_CMD_STAT (CT2_PCI_CPQ_BASE + 0x80) -#define CT2_HOSTFN_LPU1_CMD_STAT (CT2_PCI_CPQ_BASE + 0x84) -#define CT2_LPU0_HOSTFN_CMD_STAT (CT2_PCI_CPQ_BASE + 0x88) -#define CT2_LPU1_HOSTFN_CMD_STAT (CT2_PCI_CPQ_BASE + 0x8c) -#define CT2_HOSTFN_LPU0_READ_STAT (CT2_PCI_CPQ_BASE + 0x90) -#define CT2_HOSTFN_LPU1_READ_STAT (CT2_PCI_CPQ_BASE + 0x94) -#define CT2_LPU0_HOSTFN_MBOX0_MSK (CT2_PCI_CPQ_BASE + 0x98) -#define CT2_LPU1_HOSTFN_MBOX0_MSK (CT2_PCI_CPQ_BASE + 0x9C) -#define CT2_HOST_SEM0_REG 0x000148f0 -#define CT2_HOST_SEM1_REG 0x000148f4 -#define CT2_HOST_SEM2_REG 0x000148f8 -#define CT2_HOST_SEM3_REG 0x000148fc -#define CT2_HOST_SEM4_REG 0x00014900 -#define CT2_HOST_SEM5_REG 0x00014904 -#define CT2_HOST_SEM6_REG 0x00014908 -#define CT2_HOST_SEM7_REG 0x0001490c -#define CT2_HOST_SEM0_INFO_REG 0x000148b0 -#define CT2_HOST_SEM1_INFO_REG 0x000148b4 -#define CT2_HOST_SEM2_INFO_REG 0x000148b8 -#define CT2_HOST_SEM3_INFO_REG 0x000148bc -#define CT2_HOST_SEM4_INFO_REG 0x000148c0 -#define CT2_HOST_SEM5_INFO_REG 0x000148c4 -#define CT2_HOST_SEM6_INFO_REG 0x000148c8 -#define CT2_HOST_SEM7_INFO_REG 0x000148cc - -#define CT2_APP_PLL_LCLK_CTL_REG 0x00014808 -#define __APP_LPUCLK_HALFSPEED 0x40000000 -#define __APP_PLL_LCLK_LOAD 0x20000000 -#define __APP_PLL_LCLK_FBCNT_MK 0x1fe00000 -#define __APP_PLL_LCLK_FBCNT_SH 21 -#define __APP_PLL_LCLK_FBCNT(_v) ((_v) << __APP_PLL_SCLK_FBCNT_SH) -enum { - __APP_PLL_LCLK_FBCNT_425_MHZ = 6, - __APP_PLL_LCLK_FBCNT_468_MHZ = 4, -}; -#define __APP_PLL_LCLK_EXTFB 0x00000800 -#define __APP_PLL_LCLK_ENOUTS 0x00000400 -#define __APP_PLL_LCLK_RATE 0x00000010 -#define CT2_APP_PLL_SCLK_CTL_REG 0x0001480c -#define __P_SCLK_PLL_LOCK 0x80000000 -#define __APP_PLL_SCLK_REFCLK_SEL 0x40000000 -#define __APP_PLL_SCLK_CLK_DIV2 0x20000000 -#define __APP_PLL_SCLK_LOAD 0x10000000 -#define __APP_PLL_SCLK_FBCNT_MK 0x0ff00000 -#define __APP_PLL_SCLK_FBCNT_SH 20 -#define __APP_PLL_SCLK_FBCNT(_v) ((_v) << __APP_PLL_SCLK_FBCNT_SH) -enum { - __APP_PLL_SCLK_FBCNT_NORM = 6, - __APP_PLL_SCLK_FBCNT_10G_FC = 10, -}; -#define __APP_PLL_SCLK_EXTFB 0x00000800 -#define __APP_PLL_SCLK_ENOUTS 0x00000400 -#define __APP_PLL_SCLK_RATE 0x00000010 -#define CT2_PCIE_MISC_REG 0x00014804 -#define __ETH_CLK_ENABLE_PORT1 0x00000010 -#define CT2_CHIP_MISC_PRG 0x000148a4 -#define __ETH_CLK_ENABLE_PORT0 0x00004000 -#define __APP_LPU_SPEED 0x00000002 -#define CT2_MBIST_STAT_REG 0x00014818 -#define CT2_MBIST_CTL_REG 0x0001481c -#define CT2_PMM_1T_CONTROL_REG_P0 0x0002381c -#define __PMM_1T_PNDB_P 0x00000002 -#define CT2_PMM_1T_CONTROL_REG_P1 0x00023c1c -#define CT2_WGN_STATUS 0x00014990 -#define __WGN_READY 0x00000400 -#define __GLBL_PF_VF_CFG_RDY 0x00000200 -#define CT2_NFC_CSR_SET_REG 0x00027424 -#define __HALT_NFC_CONTROLLER 0x00000002 -#define __NFC_CONTROLLER_HALTED 0x00001000 - -#define CT2_CSI_MAC0_CONTROL_REG 0x000270d0 -#define __CSI_MAC_RESET 0x00000010 -#define __CSI_MAC_AHB_RESET 0x00000008 -#define CT2_CSI_MAC1_CONTROL_REG 0x000270d4 -#define CT2_CSI_MAC_CONTROL_REG(__n) \ - (CT2_CSI_MAC0_CONTROL_REG + \ - (__n) * (CT2_CSI_MAC1_CONTROL_REG - CT2_CSI_MAC0_CONTROL_REG)) - -/* - * Name semaphore registers based on usage - */ -#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG -#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG -#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG -#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG -#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG -#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG - -/* - * CT2 semaphore register locations changed - */ -#define CT2_BFA_IOC0_HBEAT_REG CT2_HOST_SEM0_INFO_REG -#define CT2_BFA_IOC0_STATE_REG CT2_HOST_SEM1_INFO_REG -#define CT2_BFA_IOC1_HBEAT_REG CT2_HOST_SEM2_INFO_REG -#define CT2_BFA_IOC1_STATE_REG CT2_HOST_SEM3_INFO_REG -#define CT2_BFA_FW_USE_COUNT CT2_HOST_SEM4_INFO_REG -#define CT2_BFA_IOC_FAIL_SYNC CT2_HOST_SEM5_INFO_REG - -#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) -#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) - -/* - * And corresponding host interrupt status bit field defines - */ -#define __HFN_INT_CPE_Q0 0x00000001U -#define __HFN_INT_CPE_Q1 0x00000002U -#define __HFN_INT_CPE_Q2 0x00000004U -#define __HFN_INT_CPE_Q3 0x00000008U -#define __HFN_INT_CPE_Q4 0x00000010U -#define __HFN_INT_CPE_Q5 0x00000020U -#define __HFN_INT_CPE_Q6 0x00000040U -#define __HFN_INT_CPE_Q7 0x00000080U -#define __HFN_INT_RME_Q0 0x00000100U -#define __HFN_INT_RME_Q1 0x00000200U -#define __HFN_INT_RME_Q2 0x00000400U -#define __HFN_INT_RME_Q3 0x00000800U -#define __HFN_INT_RME_Q4 0x00001000U -#define __HFN_INT_RME_Q5 0x00002000U -#define __HFN_INT_RME_Q6 0x00004000U -#define __HFN_INT_RME_Q7 0x00008000U -#define __HFN_INT_ERR_EMC 0x00010000U -#define __HFN_INT_ERR_LPU0 0x00020000U -#define __HFN_INT_ERR_LPU1 0x00040000U -#define __HFN_INT_ERR_PSS 0x00080000U -#define __HFN_INT_MBOX_LPU0 0x00100000U -#define __HFN_INT_MBOX_LPU1 0x00200000U -#define __HFN_INT_MBOX1_LPU0 0x00400000U -#define __HFN_INT_MBOX1_LPU1 0x00800000U -#define __HFN_INT_LL_HALT 0x01000000U -#define __HFN_INT_CPE_MASK 0x000000ffU -#define __HFN_INT_RME_MASK 0x0000ff00U -#define __HFN_INT_ERR_MASK \ - (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | __HFN_INT_ERR_LPU1 | \ - __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT) -#define __HFN_INT_FN0_MASK \ - (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | __HFN_INT_CPE_Q2 | \ - __HFN_INT_CPE_Q3 | __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | \ - __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | __HFN_INT_MBOX_LPU0) -#define __HFN_INT_FN1_MASK \ - (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | __HFN_INT_CPE_Q6 | \ - __HFN_INT_CPE_Q7 | __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | \ - __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | __HFN_INT_MBOX_LPU1) - -/* - * Host interrupt status defines for catapult-2 - */ -#define __HFN_INT_MBOX_LPU0_CT2 0x00010000U -#define __HFN_INT_MBOX_LPU1_CT2 0x00020000U -#define __HFN_INT_ERR_PSS_CT2 0x00040000U -#define __HFN_INT_ERR_LPU0_CT2 0x00080000U -#define __HFN_INT_ERR_LPU1_CT2 0x00100000U -#define __HFN_INT_CPQ_HALT_CT2 0x00200000U -#define __HFN_INT_ERR_WGN_CT2 0x00400000U -#define __HFN_INT_ERR_LEHRX_CT2 0x00800000U -#define __HFN_INT_ERR_LEHTX_CT2 0x01000000U -#define __HFN_INT_ERR_MASK_CT2 \ - (__HFN_INT_ERR_PSS_CT2 | __HFN_INT_ERR_LPU0_CT2 | \ - __HFN_INT_ERR_LPU1_CT2 | __HFN_INT_CPQ_HALT_CT2 | \ - __HFN_INT_ERR_WGN_CT2 | __HFN_INT_ERR_LEHRX_CT2 | \ - __HFN_INT_ERR_LEHTX_CT2) -#define __HFN_INT_FN0_MASK_CT2 \ - (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | __HFN_INT_CPE_Q2 | \ - __HFN_INT_CPE_Q3 | __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | \ - __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | __HFN_INT_MBOX_LPU0_CT2) -#define __HFN_INT_FN1_MASK_CT2 \ - (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | __HFN_INT_CPE_Q6 | \ - __HFN_INT_CPE_Q7 | __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | \ - __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | __HFN_INT_MBOX_LPU1_CT2) - -/* - * asic memory map. - */ -#define PSS_SMEM_PAGE_START 0x8000 -#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15)) -#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff) - -#endif /* __BFI_REG_H__ */ diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc.h b/trunk/drivers/scsi/bnx2fc/bnx2fc.h index d924236e1b91..907672e86063 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc.h +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc.h @@ -152,6 +152,7 @@ struct bnx2fc_percpu_s { spinlock_t fp_work_lock; }; + struct bnx2fc_hba { struct list_head link; struct cnic_dev *cnic; @@ -178,7 +179,6 @@ struct bnx2fc_hba { #define BNX2FC_CTLR_INIT_DONE 1 #define BNX2FC_CREATE_DONE 2 struct fcoe_ctlr ctlr; - struct list_head vports; u8 vlan_enabled; int vlan_id; u32 next_conn_id; @@ -232,11 +232,6 @@ struct bnx2fc_hba { #define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_hba, ctlr) -struct bnx2fc_lport { - struct list_head list; - struct fc_lport *lport; -}; - struct bnx2fc_cmd_mgr { struct bnx2fc_hba *hba; u16 next_idx; @@ -433,7 +428,6 @@ struct bnx2fc_work { struct bnx2fc_unsol_els { struct fc_lport *lport; struct fc_frame *fp; - struct bnx2fc_hba *hba; struct work_struct unsol_els_work; }; diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index a97aff3a0662..9eebaebdaa78 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -679,9 +679,6 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport) case SPEED_1000: lport->link_speed = FC_PORTSPEED_1GBIT; break; - case SPEED_2500: - lport->link_speed = FC_PORTSPEED_2GBIT; - break; case SPEED_10000: lport->link_speed = FC_PORTSPEED_10GBIT; break; @@ -1234,7 +1231,6 @@ static int bnx2fc_interface_setup(struct bnx2fc_hba *hba, hba->ctlr.get_src_addr = bnx2fc_get_src_mac; set_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done); - INIT_LIST_HEAD(&hba->vports); rc = bnx2fc_netdev_setup(hba); if (rc) goto setup_err; @@ -1271,15 +1267,8 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, struct fcoe_port *port; struct Scsi_Host *shost; struct fc_vport *vport = dev_to_vport(parent); - struct bnx2fc_lport *blport; int rc = 0; - blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL); - if (!blport) { - BNX2FC_HBA_DBG(hba->ctlr.lp, "Unable to alloc bnx2fc_lport\n"); - return NULL; - } - /* Allocate Scsi_Host structure */ if (!npiv) lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port)); @@ -1288,7 +1277,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, if (!lport) { printk(KERN_ERR PFX "could not allocate scsi host structure\n"); - goto free_blport; + return NULL; } shost = lport->host; port = lport_priv(lport); @@ -1344,20 +1333,12 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, } bnx2fc_interface_get(hba); - - spin_lock_bh(&hba->hba_lock); - blport->lport = lport; - list_add_tail(&blport->list, &hba->vports); - spin_unlock_bh(&hba->hba_lock); - return lport; shost_err: scsi_remove_host(shost); lp_config_err: scsi_host_put(lport->host); -free_blport: - kfree(blport); return NULL; } @@ -1373,7 +1354,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) { struct fcoe_port *port = lport_priv(lport); struct bnx2fc_hba *hba = port->priv; - struct bnx2fc_lport *blport, *tmp; BNX2FC_HBA_DBG(hba->ctlr.lp, "ENTERED bnx2fc_if_destroy\n"); /* Stop the transmit retry timer */ @@ -1398,15 +1378,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) /* Free memory used by statistical counters */ fc_lport_free_stats(lport); - spin_lock_bh(&hba->hba_lock); - list_for_each_entry_safe(blport, tmp, &hba->vports, list) { - if (blport->lport == lport) { - list_del(&blport->list); - kfree(blport); - } - } - spin_unlock_bh(&hba->hba_lock); - /* Release Scsi_Host */ scsi_host_put(lport->host); diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 09bdd9b88d1a..d8e8a825560d 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -486,36 +486,16 @@ int bnx2fc_send_session_destroy_req(struct bnx2fc_hba *hba, return rc; } -static bool is_valid_lport(struct bnx2fc_hba *hba, struct fc_lport *lport) -{ - struct bnx2fc_lport *blport; - - spin_lock_bh(&hba->hba_lock); - list_for_each_entry(blport, &hba->vports, list) { - if (blport->lport == lport) { - spin_unlock_bh(&hba->hba_lock); - return true; - } - } - spin_unlock_bh(&hba->hba_lock); - return false; - -} - - static void bnx2fc_unsol_els_work(struct work_struct *work) { struct bnx2fc_unsol_els *unsol_els; struct fc_lport *lport; - struct bnx2fc_hba *hba; struct fc_frame *fp; unsol_els = container_of(work, struct bnx2fc_unsol_els, unsol_els_work); lport = unsol_els->lport; fp = unsol_els->fp; - hba = unsol_els->hba; - if (is_valid_lport(hba, lport)) - fc_exch_recv(lport, fp); + fc_exch_recv(lport, fp); kfree(unsol_els); } @@ -525,7 +505,6 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, { struct fcoe_port *port = tgt->port; struct fc_lport *lport = port->lport; - struct bnx2fc_hba *hba = port->priv; struct bnx2fc_unsol_els *unsol_els; struct fc_frame_header *fh; struct fc_frame *fp; @@ -586,7 +565,6 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, fr_eof(fp) = FC_EOF_T; fr_crc(fp) = cpu_to_le32(~crc); unsol_els->lport = lport; - unsol_els->hba = hba; unsol_els->fp = fp; INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work); queue_work(bnx2fc_wq, &unsol_els->unsol_els_work); diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c index 45eba6d609c9..5dc4205ed8af 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1743,6 +1743,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, printk(KERN_ERR PFX "SCp.ptr is NULL\n"); return; } + io_req->sc_cmd = NULL; if (io_req->on_active_queue) { list_del_init(&io_req->link); @@ -1762,7 +1763,6 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, } bnx2fc_unmap_sg_list(io_req); - io_req->sc_cmd = NULL; switch (io_req->fcp_status) { case FC_GOOD: diff --git a/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h index 57515f1f1690..15673cc786ff 100644 --- a/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h +++ b/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h @@ -1,6 +1,6 @@ /* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom 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 diff --git a/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h index 72118db89a20..71890a063cd3 100644 --- a/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h +++ b/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h @@ -1,6 +1,6 @@ /* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom 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 diff --git a/trunk/drivers/scsi/bnx2i/bnx2i.h b/trunk/drivers/scsi/bnx2i/bnx2i.h index dc5700765db4..e7cb7ecf6847 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i.h +++ b/trunk/drivers/scsi/bnx2i/bnx2i.h @@ -1,6 +1,6 @@ /* bnx2i.h: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -22,14 +22,11 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include #include @@ -205,13 +202,10 @@ struct io_bdt { /** * bnx2i_cmd - iscsi command structure * - * @hdr: iSCSI header - * @conn: iscsi_conn pointer * @scsi_cmd: SCSI-ML task pointer corresponding to this iscsi cmd * @sg: SG list * @io_tbl: buffer descriptor (BD) table * @bd_tbl_dma: buffer descriptor (BD) table's dma address - * @req: bnx2i specific command request struct */ struct bnx2i_cmd { struct iscsi_hdr hdr; @@ -235,7 +229,6 @@ struct bnx2i_cmd { * @gen_pdu: login/nopout/logout pdu resources * @violation_notified: bit mask used to track iscsi error/warning messages * already printed out - * @work_cnt: keeps track of the number of outstanding work * * iSCSI connection structure */ @@ -259,8 +252,6 @@ struct bnx2i_conn { */ struct generic_pdu_resc gen_pdu; u64 violation_notified; - - atomic_t work_cnt; }; @@ -670,6 +661,7 @@ enum { * @hba: adapter to which this connection belongs * @conn: iscsi connection this EP is linked to * @cls_ep: associated iSCSI endpoint pointer + * @sess: iscsi session this EP is linked to * @cm_sk: cnic sock struct * @hba_age: age to detect if 'iscsid' issues ep_disconnect() * after HBA reset is completed by bnx2i/cnic/bnx2 @@ -695,7 +687,7 @@ struct bnx2i_endpoint { u32 hba_age; u32 state; unsigned long timestamp; - atomic_t num_active_cmds; + int num_active_cmds; u32 ec_shift; struct qp_info qp; @@ -708,19 +700,6 @@ struct bnx2i_endpoint { }; -struct bnx2i_work { - struct list_head list; - struct iscsi_session *session; - struct bnx2i_conn *bnx2i_conn; - struct cqe cqe; -}; - -struct bnx2i_percpu_s { - struct task_struct *iothread; - struct list_head work_list; - spinlock_t p_work_lock; -}; - /* Global variables */ extern unsigned int error_mask1, error_mask2; @@ -804,7 +783,7 @@ extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list( struct bnx2i_hba *hba, u32 iscsi_cid); extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep); -extern int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); +extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep); @@ -814,8 +793,4 @@ extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn); extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn); extern void bnx2i_print_recv_state(struct bnx2i_conn *conn); -extern int bnx2i_percpu_io_thread(void *arg); -extern int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe); #endif diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c b/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c index 030a96c646c3..372d30c099cc 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -1,6 +1,6 @@ /* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -17,8 +17,6 @@ #include #include "bnx2i.h" -DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); - /** * bnx2i_get_cid_num - get cid from ep * @ep: endpoint pointer @@ -133,16 +131,16 @@ static void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code) * the driver. EQ event is generated CQ index is hit or at least 1 CQ is * outstanding and on chip timer expires */ -int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) +void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) { struct bnx2i_5771x_cq_db *cq_db; u16 cq_index; - u16 next_index = 0; + u16 next_index; u32 num_active_cmds; /* Coalesce CQ entries only on 10G devices */ if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) - return 0; + return; /* Do not update CQ DB multiple times before firmware writes * '0xFFFF' to CQDB->SQN field. Deviation may cause spurious @@ -152,17 +150,16 @@ int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) if (action != CNIC_ARM_CQE_FP) if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF) - return 0; + return; if (action == CNIC_ARM_CQE || action == CNIC_ARM_CQE_FP) { - num_active_cmds = atomic_read(&ep->num_active_cmds); + num_active_cmds = ep->num_active_cmds; if (num_active_cmds <= event_coal_min) next_index = 1; - else { - next_index = num_active_cmds >> ep->ec_shift; - if (next_index > num_active_cmds - event_coal_min) - next_index = num_active_cmds - event_coal_min; - } + else + next_index = event_coal_min + + ((num_active_cmds - event_coal_min) >> + ep->ec_shift); if (!next_index) next_index = 1; cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1; @@ -173,7 +170,6 @@ int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) cq_db->sqn[0] = cq_index; } - return next_index; } @@ -269,7 +265,7 @@ static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count) struct bnx2i_5771x_sq_rq_db *sq_db; struct bnx2i_endpoint *ep = bnx2i_conn->ep; - atomic_inc(&ep->num_active_cmds); + ep->num_active_cmds++; wmb(); /* flush SQ WQE memory before the doorbell is rung */ if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt; @@ -434,7 +430,7 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn, default: tmfabort_wqe->ref_itt = RESERVED_ITT; } - memcpy(scsi_lun, &tmfabort_hdr->lun, sizeof(struct scsi_lun)); + memcpy(scsi_lun, tmfabort_hdr->lun, sizeof(struct scsi_lun)); tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]); tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]); @@ -551,7 +547,7 @@ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn, nopout_wqe->op_code = nopout_hdr->opcode; nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL; - memcpy(nopout_wqe->lun, &nopout_hdr->lun, 8); + memcpy(nopout_wqe->lun, nopout_hdr->lun, 8); if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { u32 tmp = nopout_wqe->lun[0]; @@ -1335,15 +1331,14 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba) /** * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion. - * @session: iscsi session - * @bnx2i_conn: bnx2i connection + * @conn: iscsi connection * @cqe: pointer to newly DMA'ed CQE entry for processing * * process SCSI CMD Response CQE & complete the request to SCSI-ML */ -int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) +static int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) { struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; struct bnx2i_cmd_response *resp_cqe; @@ -1353,7 +1348,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, u32 datalen = 0; resp_cqe = (struct bnx2i_cmd_response *)cqe; - spin_lock_bh(&session->lock); + spin_lock(&session->lock); task = iscsi_itt_to_task(conn, resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX); if (!task) @@ -1414,7 +1409,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data, datalen); fail: - spin_unlock_bh(&session->lock); + spin_unlock(&session->lock); return 0; } @@ -1716,7 +1711,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session, hdr->flags = ISCSI_FLAG_CMD_FINAL; hdr->itt = task->hdr->itt; hdr->ttt = cpu_to_be32(nop_in->ttt); - memcpy(&hdr->lun, nop_in->lun, 8); + memcpy(hdr->lun, nop_in->lun, 8); } done: __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); @@ -1759,7 +1754,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session, resp_hdr->opcode = async_cqe->op_code; resp_hdr->flags = 0x80; - memcpy(&resp_hdr->lun, async_cqe->lun, 8); + memcpy(resp_hdr->lun, async_cqe->lun, 8); resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn); resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn); @@ -1841,136 +1836,21 @@ static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session, } -/** - * bnx2i_percpu_io_thread - thread per cpu for ios - * - * @arg: ptr to bnx2i_percpu_info structure - */ -int bnx2i_percpu_io_thread(void *arg) -{ - struct bnx2i_percpu_s *p = arg; - struct bnx2i_work *work, *tmp; - LIST_HEAD(work_list); - - set_user_nice(current, -20); - - while (!kthread_should_stop()) { - spin_lock_bh(&p->p_work_lock); - while (!list_empty(&p->work_list)) { - list_splice_init(&p->work_list, &work_list); - spin_unlock_bh(&p->p_work_lock); - - list_for_each_entry_safe(work, tmp, &work_list, list) { - list_del_init(&work->list); - /* work allocated in the bh, freed here */ - bnx2i_process_scsi_cmd_resp(work->session, - work->bnx2i_conn, - &work->cqe); - atomic_dec(&work->bnx2i_conn->work_cnt); - kfree(work); - } - spin_lock_bh(&p->p_work_lock); - } - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_bh(&p->p_work_lock); - schedule(); - } - __set_current_state(TASK_RUNNING); - - return 0; -} - - -/** - * bnx2i_queue_scsi_cmd_resp - queue cmd completion to the percpu thread - * @bnx2i_conn: bnx2i connection - * - * this function is called by generic KCQ handler to queue all pending cmd - * completion CQEs - * - * The implementation is to queue the cmd response based on the - * last recorded command for the given connection. The - * cpu_id gets recorded upon task_xmit. No out-of-order completion! - */ -static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct bnx2i_nop_in_msg *cqe) -{ - struct bnx2i_work *bnx2i_work = NULL; - struct bnx2i_percpu_s *p = NULL; - struct iscsi_task *task; - struct scsi_cmnd *sc; - int rc = 0; - int cpu; - - spin_lock(&session->lock); - task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, - cqe->itt & ISCSI_CMD_RESPONSE_INDEX); - if (!task) { - spin_unlock(&session->lock); - return -EINVAL; - } - sc = task->sc; - spin_unlock(&session->lock); - - if (!blk_rq_cpu_valid(sc->request)) - cpu = smp_processor_id(); - else - cpu = sc->request->cpu; - - p = &per_cpu(bnx2i_percpu, cpu); - spin_lock(&p->p_work_lock); - if (unlikely(!p->iothread)) { - rc = -EINVAL; - goto err; - } - /* Alloc and copy to the cqe */ - bnx2i_work = kzalloc(sizeof(struct bnx2i_work), GFP_ATOMIC); - if (bnx2i_work) { - INIT_LIST_HEAD(&bnx2i_work->list); - bnx2i_work->session = session; - bnx2i_work->bnx2i_conn = bnx2i_conn; - memcpy(&bnx2i_work->cqe, cqe, sizeof(struct cqe)); - list_add_tail(&bnx2i_work->list, &p->work_list); - atomic_inc(&bnx2i_conn->work_cnt); - wake_up_process(p->iothread); - spin_unlock(&p->p_work_lock); - goto done; - } else - rc = -ENOMEM; -err: - spin_unlock(&p->p_work_lock); - bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, (struct cqe *)cqe); -done: - return rc; -} - /** * bnx2i_process_new_cqes - process newly DMA'ed CQE's - * @bnx2i_conn: bnx2i connection + * @bnx2i_conn: iscsi connection * * this function is called by generic KCQ handler to process all pending CQE's */ -static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) +static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) { struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; struct iscsi_session *session = conn->session; - struct qp_info *qp; + struct qp_info *qp = &bnx2i_conn->ep->qp; struct bnx2i_nop_in_msg *nopin; int tgt_async_msg; - int cqe_cnt = 0; - if (bnx2i_conn->ep == NULL) - return 0; - - qp = &bnx2i_conn->ep->qp; - - if (!qp->cq_virt) { - printk(KERN_ALERT "bnx2i (%s): cq resr freed in bh execution!", - bnx2i_conn->hba->netdev->name); - goto out; - } while (1) { nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe; if (nopin->cq_req_sn != qp->cqe_exp_seq_sn) @@ -1993,9 +1873,8 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) switch (nopin->op_code) { case ISCSI_OP_SCSI_CMD_RSP: case ISCSI_OP_SCSI_DATA_IN: - /* Run the kthread engine only for data cmds - All other cmds will be completed in this bh! */ - bnx2i_queue_scsi_cmd_resp(session, bnx2i_conn, nopin); + bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, + qp->cq_cons_qe); break; case ISCSI_OP_LOGIN_RSP: bnx2i_process_login_resp(session, bnx2i_conn, @@ -2039,21 +1918,13 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", nopin->op_code); } - if (!tgt_async_msg) { - if (!atomic_read(&bnx2i_conn->ep->num_active_cmds)) - printk(KERN_ALERT "bnx2i (%s): no active cmd! " - "op 0x%x\n", - bnx2i_conn->hba->netdev->name, - nopin->op_code); - else - atomic_dec(&bnx2i_conn->ep->num_active_cmds); - } + if (!tgt_async_msg) + bnx2i_conn->ep->num_active_cmds--; cqe_out: /* clear out in production version only, till beta keep opcode * field intact, will be helpful in debugging (context dump) * nopin->op_code = 0; */ - cqe_cnt++; qp->cqe_exp_seq_sn++; if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1)) qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN; @@ -2066,8 +1937,6 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) qp->cq_cons_idx++; } } -out: - return cqe_cnt; } /** @@ -2083,7 +1952,6 @@ static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, { struct bnx2i_conn *bnx2i_conn; u32 iscsi_cid; - int nxt_idx; iscsi_cid = new_cqe_kcqe->iscsi_conn_id; bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); @@ -2096,12 +1964,9 @@ static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid); return; } - bnx2i_process_new_cqes(bnx2i_conn); - nxt_idx = bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, - CNIC_ARM_CQE_FP); - if (nxt_idx && nxt_idx == bnx2i_process_new_cqes(bnx2i_conn)) - bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP); + bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP); + bnx2i_process_new_cqes(bnx2i_conn); } @@ -2447,7 +2312,7 @@ static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba, printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid " "opcode\n", hba->netdev->name); else if (ofld_kcqe->completion_status == - ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY) + ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY) /* error status code valid only for 5771x chipset */ ep->state = EP_STATE_OFLD_FAILED_CID_BUSY; else @@ -2652,7 +2517,7 @@ static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk) static int bnx2i_send_nl_mesg(void *context, u32 msg_type, - char *buf, u16 buflen) + char *buf, u16 buflen) { struct bnx2i_hba *hba = context; int rc; diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_init.c b/trunk/drivers/scsi/bnx2i/bnx2i_init.c index 1a947f1b9729..6973413e91ec 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_init.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_init.c @@ -1,6 +1,6 @@ /* bnx2i.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -18,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); static u32 adapter_count; #define DRV_MODULE_NAME "bnx2i" -#define DRV_MODULE_VERSION "2.7.0.3" -#define DRV_MODULE_RELDATE "Jun 15, 2011" +#define DRV_MODULE_VERSION "2.6.2.3" +#define DRV_MODULE_RELDATE "Dec 31, 2010" static char version[] __devinitdata = "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ @@ -40,7 +40,7 @@ unsigned int event_coal_min = 24; module_param(event_coal_min, int, 0664); MODULE_PARM_DESC(event_coal_min, "Event Coalescing Minimum Commands"); -unsigned int event_coal_div = 2; +unsigned int event_coal_div = 1; module_param(event_coal_div, int, 0664); MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor"); @@ -66,15 +66,6 @@ MODULE_PARM_DESC(rq_size, "Configure RQ size"); u64 iscsi_error_mask = 0x00; -DEFINE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); - -static int bnx2i_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu); -/* notification function for CPU hotplug events */ -static struct notifier_block bnx2i_cpu_notifier = { - .notifier_call = bnx2i_cpu_callback, -}; - /** * bnx2i_identify_device - identifies NetXtreme II device type @@ -181,14 +172,21 @@ void bnx2i_start(void *handle) struct bnx2i_hba *hba = handle; int i = HZ; - /* - * We should never register devices that don't support iSCSI - * (see bnx2i_init_one), so something is wrong if we try to - * start a iSCSI adapter on hardware with 0 supported iSCSI - * connections - */ - BUG_ON(!hba->cnic->max_iscsi_conn); + if (!hba->cnic->max_iscsi_conn) { + printk(KERN_ALERT "bnx2i: dev %s does not support " + "iSCSI\n", hba->netdev->name); + if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { + mutex_lock(&bnx2i_dev_lock); + list_del_init(&hba->link); + adapter_count--; + hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); + clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); + mutex_unlock(&bnx2i_dev_lock); + bnx2i_free_hba(hba); + } + return; + } bnx2i_send_fw_iscsi_init_msg(hba); while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) msleep(BNX2I_INIT_POLL_TIME); @@ -292,13 +290,6 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) int rc; mutex_lock(&bnx2i_dev_lock); - if (!cnic->max_iscsi_conn) { - printk(KERN_ALERT "bnx2i: dev %s does not support " - "iSCSI\n", hba->netdev->name); - rc = -EOPNOTSUPP; - goto out; - } - hba->cnic = cnic; rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); if (!rc) { @@ -316,7 +307,6 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) else printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc); -out: mutex_unlock(&bnx2i_dev_lock); return rc; @@ -380,91 +370,6 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) } -/** - * bnx2i_percpu_thread_create - Create a receive thread for an - * online CPU - * - * @cpu: cpu index for the online cpu - */ -static void bnx2i_percpu_thread_create(unsigned int cpu) -{ - struct bnx2i_percpu_s *p; - struct task_struct *thread; - - p = &per_cpu(bnx2i_percpu, cpu); - - thread = kthread_create(bnx2i_percpu_io_thread, (void *)p, - "bnx2i_thread/%d", cpu); - /* bind thread to the cpu */ - if (likely(!IS_ERR(thread))) { - kthread_bind(thread, cpu); - p->iothread = thread; - wake_up_process(thread); - } -} - - -static void bnx2i_percpu_thread_destroy(unsigned int cpu) -{ - struct bnx2i_percpu_s *p; - struct task_struct *thread; - struct bnx2i_work *work, *tmp; - - /* Prevent any new work from being queued for this CPU */ - p = &per_cpu(bnx2i_percpu, cpu); - spin_lock_bh(&p->p_work_lock); - thread = p->iothread; - p->iothread = NULL; - - /* Free all work in the list */ - list_for_each_entry_safe(work, tmp, &p->work_list, list) { - list_del_init(&work->list); - bnx2i_process_scsi_cmd_resp(work->session, - work->bnx2i_conn, &work->cqe); - kfree(work); - } - - spin_unlock_bh(&p->p_work_lock); - if (thread) - kthread_stop(thread); -} - - -/** - * bnx2i_cpu_callback - Handler for CPU hotplug events - * - * @nfb: The callback data block - * @action: The event triggering the callback - * @hcpu: The index of the CPU that the event is for - * - * This creates or destroys per-CPU data for iSCSI - * - * Returns NOTIFY_OK always. - */ -static int bnx2i_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned cpu = (unsigned long)hcpu; - - switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - printk(KERN_INFO "bnx2i: CPU %x online: Create Rx thread\n", - cpu); - bnx2i_percpu_thread_create(cpu); - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - printk(KERN_INFO "CPU %x offline: Remove Rx thread\n", cpu); - bnx2i_percpu_thread_destroy(cpu); - break; - default: - break; - } - return NOTIFY_OK; -} - - /** * bnx2i_mod_init - module init entry point * @@ -475,8 +380,6 @@ static int bnx2i_cpu_callback(struct notifier_block *nfb, static int __init bnx2i_mod_init(void) { int err; - unsigned cpu = 0; - struct bnx2i_percpu_s *p; printk(KERN_INFO "%s", version); @@ -499,20 +402,6 @@ static int __init bnx2i_mod_init(void) goto unreg_xport; } - /* Create percpu kernel threads to handle iSCSI I/O completions */ - for_each_possible_cpu(cpu) { - p = &per_cpu(bnx2i_percpu, cpu); - INIT_LIST_HEAD(&p->work_list); - spin_lock_init(&p->p_work_lock); - p->iothread = NULL; - } - - for_each_online_cpu(cpu) - bnx2i_percpu_thread_create(cpu); - - /* Initialize per CPU interrupt thread */ - register_hotcpu_notifier(&bnx2i_cpu_notifier); - return 0; unreg_xport: @@ -533,7 +422,6 @@ static int __init bnx2i_mod_init(void) static void __exit bnx2i_mod_exit(void) { struct bnx2i_hba *hba; - unsigned cpu = 0; mutex_lock(&bnx2i_dev_lock); while (!list_empty(&adapter_list)) { @@ -551,11 +439,6 @@ static void __exit bnx2i_mod_exit(void) } mutex_unlock(&bnx2i_dev_lock); - unregister_hotcpu_notifier(&bnx2i_cpu_notifier); - - for_each_online_cpu(cpu) - bnx2i_percpu_thread_destroy(cpu); - iscsi_unregister_transport(&bnx2i_iscsi_transport); cnic_unregister_driver(CNIC_ULP_ISCSI); } diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c b/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c index 5c55a75ae597..041928b23cb0 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1,7 +1,7 @@ /* * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -27,7 +27,6 @@ static struct scsi_host_template bnx2i_host_template; */ static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */ -DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); static int bnx2i_adapter_ready(struct bnx2i_hba *hba) { @@ -1215,8 +1214,7 @@ static int bnx2i_task_xmit(struct iscsi_task *task) struct bnx2i_cmd *cmd = task->dd_data; struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr; - if (atomic_read(&bnx2i_conn->ep->num_active_cmds) + 1 > - hba->max_sqes) + if (bnx2i_conn->ep->num_active_cmds + 1 > hba->max_sqes) return -ENOMEM; /* @@ -1356,9 +1354,6 @@ bnx2i_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid) bnx2i_conn = conn->dd_data; bnx2i_conn->cls_conn = cls_conn; bnx2i_conn->hba = hba; - - atomic_set(&bnx2i_conn->work_cnt, 0); - /* 'ep' ptr will be assigned in bind() call */ bnx2i_conn->ep = NULL; init_completion(&bnx2i_conn->cmd_cleanup_cmpl); @@ -1462,34 +1457,11 @@ static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn) struct bnx2i_conn *bnx2i_conn = conn->dd_data; struct Scsi_Host *shost; struct bnx2i_hba *hba; - struct bnx2i_work *work, *tmp; - unsigned cpu = 0; - struct bnx2i_percpu_s *p; shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn)); hba = iscsi_host_priv(shost); bnx2i_conn_free_login_resources(hba, bnx2i_conn); - - if (atomic_read(&bnx2i_conn->work_cnt)) { - for_each_online_cpu(cpu) { - p = &per_cpu(bnx2i_percpu, cpu); - spin_lock_bh(&p->p_work_lock); - list_for_each_entry_safe(work, tmp, - &p->work_list, list) { - if (work->session == conn->session && - work->bnx2i_conn == bnx2i_conn) { - list_del_init(&work->list); - kfree(work); - if (!atomic_dec_and_test( - &bnx2i_conn->work_cnt)) - break; - } - } - spin_unlock_bh(&p->p_work_lock); - } - } - iscsi_conn_teardown(cls_conn); } @@ -1797,7 +1769,7 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, } bnx2i_ep = ep->dd_data; - atomic_set(&bnx2i_ep->num_active_cmds, 0); + bnx2i_ep->num_active_cmds = 0; iscsi_cid = bnx2i_alloc_iscsi_cid(hba); if (iscsi_cid == -1) { printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate " @@ -2191,9 +2163,9 @@ static struct scsi_host_template bnx2i_host_template = { .eh_device_reset_handler = iscsi_eh_device_reset, .eh_target_reset_handler = iscsi_eh_recover_target, .change_queue_depth = iscsi_change_queue_depth, - .can_queue = 2048, + .can_queue = 1024, .max_sectors = 127, - .cmd_per_lun = 128, + .cmd_per_lun = 24, .this_id = -1, .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = ISCSI_MAX_BDS_PER_CMD, diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c b/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c index 83a77f7244d2..9174196d9033 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c @@ -1,6 +1,6 @@ /* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2004 - 2011 Broadcom Corporation + * Copyright (c) 2004 - 2010 Broadcom 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 diff --git a/trunk/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/trunk/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index bd22041e2789..abc7b122e050 100644 --- a/trunk/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/trunk/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -1245,7 +1245,7 @@ static int cxgb3i_ddp_init(struct cxgbi_device *cdev) struct cxgbi_ddp_info *ddp = tdev->ulp_iscsi; struct ulp_iscsi_info uinfo; unsigned int pgsz_factor[4]; - int i, err; + int err; if (ddp) { kref_get(&ddp->refcnt); @@ -1271,8 +1271,6 @@ static int cxgb3i_ddp_init(struct cxgbi_device *cdev) uinfo.tagmask = ddp->idx_mask << PPOD_IDX_SHIFT; cxgbi_ddp_page_size_factor(pgsz_factor); - for (i = 0; i < 4; i++) - uinfo.pgsz_factor[i] = pgsz_factor[i]; uinfo.ulimit = uinfo.llimit + (ddp->nppods << PPOD_SIZE_SHIFT); err = tdev->ctl(tdev, ULP_ISCSI_SET_PARAMS, &uinfo); diff --git a/trunk/drivers/scsi/fcoe/fcoe.c b/trunk/drivers/scsi/fcoe/fcoe.c index 204fa8d4b4ab..155d7b9bdeae 100644 --- a/trunk/drivers/scsi/fcoe/fcoe.c +++ b/trunk/drivers/scsi/fcoe/fcoe.c @@ -99,8 +99,7 @@ static void fcoe_destroy_work(struct work_struct *); static int fcoe_ddp_setup(struct fc_lport *, u16, struct scatterlist *, unsigned int); static int fcoe_ddp_done(struct fc_lport *, u16); -static int fcoe_ddp_target(struct fc_lport *, u16, struct scatterlist *, - unsigned int); + static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *); static bool fcoe_match(struct net_device *netdev); @@ -144,7 +143,6 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { .frame_send = fcoe_xmit, .ddp_setup = fcoe_ddp_setup, .ddp_done = fcoe_ddp_done, - .ddp_target = fcoe_ddp_target, .elsct_send = fcoe_elsct_send, .get_lesb = fcoe_get_lesb, .lport_set_port_id = fcoe_set_port_id, @@ -431,6 +429,21 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) struct fcoe_ctlr *fip = &fcoe->ctlr; u8 flogi_maddr[ETH_ALEN]; const struct net_device_ops *ops; + struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); + + FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); + + /* Logout of the fabric */ + fc_fabric_logoff(fcoe->ctlr.lp); + + /* Cleanup the fc_lport */ + fc_lport_destroy(fcoe->ctlr.lp); + + /* Stop the transmit retry timer */ + del_timer_sync(&port->timer); + + /* Free existing transmit skbs */ + fcoe_clean_pending_queue(fcoe->ctlr.lp); /* * Don't listen for Ethernet packets anymore. @@ -453,6 +466,9 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) } else dev_mc_del(netdev, FIP_ALL_ENODE_MACS); + if (!is_zero_ether_addr(port->data_src_addr)) + dev_uc_del(netdev, port->data_src_addr); + /* Tell the LLD we are done w/ FCoE */ ops = netdev->netdev_ops; if (ops->ndo_fcoe_disable) { @@ -460,8 +476,6 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" " specific feature for LLD.\n"); } - - /* Release the self-reference taken during fcoe_interface_create() */ fcoe_interface_put(fcoe); } @@ -735,27 +749,12 @@ static int fcoe_shost_config(struct fc_lport *lport, struct device *dev) * The offload EM that this routine is associated with will handle any * packets that are for SCSI read requests. * - * This has been enhanced to work when FCoE stack is operating in target - * mode. - * * Returns: True for read types I/O, otherwise returns false. */ bool fcoe_oem_match(struct fc_frame *fp) { - struct fc_frame_header *fh = fc_frame_header_get(fp); - struct fcp_cmnd *fcp; - - if (fc_fcp_is_read(fr_fsp(fp)) && - (fr_fsp(fp)->data_len > fcoe_ddp_min)) - return true; - else if (!(ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX)) { - fcp = fc_frame_payload_get(fp, sizeof(*fcp)); - if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN && - fcp && (ntohl(fcp->fc_dl) > fcoe_ddp_min) && - (fcp->fc_flags & FCP_CFL_WRDATA)) - return true; - } - return false; + return fc_fcp_is_read(fr_fsp(fp)) && + (fr_fsp(fp)->data_len > fcoe_ddp_min); } /** @@ -845,32 +844,6 @@ static inline int fcoe_em_config(struct fc_lport *lport) */ static void fcoe_if_destroy(struct fc_lport *lport) { - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - struct net_device *netdev = fcoe->netdev; - - FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); - - /* Logout of the fabric */ - fc_fabric_logoff(lport); - - /* Cleanup the fc_lport */ - fc_lport_destroy(lport); - - /* Stop the transmit retry timer */ - del_timer_sync(&port->timer); - - /* Free existing transmit skbs */ - fcoe_clean_pending_queue(lport); - - rtnl_lock(); - if (!is_zero_ether_addr(port->data_src_addr)) - dev_uc_del(netdev, port->data_src_addr); - rtnl_unlock(); - - /* Release reference held in fcoe_if_create() */ - fcoe_interface_put(fcoe); - /* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean(lport); @@ -913,28 +886,6 @@ static int fcoe_ddp_setup(struct fc_lport *lport, u16 xid, return 0; } -/** - * fcoe_ddp_target() - Call a LLD's ddp_target through the net device - * @lport: The local port to setup DDP for - * @xid: The exchange ID for this DDP transfer - * @sgl: The scatterlist describing this transfer - * @sgc: The number of sg items - * - * Returns: 0 if the DDP context was not configured - */ -static int fcoe_ddp_target(struct fc_lport *lport, u16 xid, - struct scatterlist *sgl, unsigned int sgc) -{ - struct net_device *netdev = fcoe_netdev(lport); - - if (netdev->netdev_ops->ndo_fcoe_ddp_target) - return netdev->netdev_ops->ndo_fcoe_ddp_target(netdev, xid, - sgl, sgc); - - return 0; -} - - /** * fcoe_ddp_done() - Call a LLD's ddp_done through the net device * @lport: The local port to complete DDP on @@ -1254,36 +1205,6 @@ static int fcoe_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -/** - * fcoe_select_cpu() - Selects CPU to handle post-processing of incoming - * command. - * @curr_cpu: CPU which received request - * - * This routine selects next CPU based on cpumask. - * - * Returns: int (CPU number). Caller to verify if returned CPU is online or not. - */ -static unsigned int fcoe_select_cpu(unsigned int curr_cpu) -{ - static unsigned int selected_cpu; - - if (num_online_cpus() == 1) - return curr_cpu; - /* - * Doing following check, to skip "curr_cpu (smp_processor_id)" - * from selection of CPU is intentional. This is to avoid same CPU - * doing post-processing of command. "curr_cpu" to just receive - * incoming request in case where rx_id is UNKNOWN and all other - * CPU to actually process the command(s) - */ - do { - selected_cpu = cpumask_next(selected_cpu, cpu_online_mask); - if (selected_cpu >= nr_cpu_ids) - selected_cpu = cpumask_first(cpu_online_mask); - } while (selected_cpu == curr_cpu); - return selected_cpu; -} - /** * fcoe_rcv() - Receive packets from a net device * @skb: The received packet @@ -1360,20 +1281,9 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, */ if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX) cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask; - else { + else cpu = smp_processor_id(); - if ((fh->fh_type == FC_TYPE_FCP) && - (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) { - do { - cpu = fcoe_select_cpu(cpu); - } while (!cpu_online(cpu)); - } else if ((fh->fh_type == FC_TYPE_FCP) && - (ntohs(fh->fh_rx_id) != FC_XID_UNKNOWN)) { - cpu = ntohs(fh->fh_rx_id) & fc_cpu_mask; - } else - cpu = smp_processor_id(); - } fps = &per_cpu(fcoe_percpu, cpu); spin_lock_bh(&fps->fcoe_rx_list.lock); if (unlikely(!fps->thread)) { @@ -1823,6 +1733,7 @@ static int fcoe_device_notification(struct notifier_block *notifier, case NETDEV_UNREGISTER: list_del(&fcoe->list); port = lport_priv(fcoe->ctlr.lp); + fcoe_interface_cleanup(fcoe); queue_work(fcoe_wq, &port->destroy_work); goto out; break; @@ -1916,22 +1827,22 @@ static int fcoe_destroy(struct net_device *netdev) { struct fcoe_interface *fcoe; struct fc_lport *lport; - struct fcoe_port *port; int rc = 0; mutex_lock(&fcoe_config_mutex); rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); if (!fcoe) { + rtnl_unlock(); rc = -ENODEV; goto out_nodev; } lport = fcoe->ctlr.lp; - port = lport_priv(lport); list_del(&fcoe->list); - queue_work(fcoe_wq, &port->destroy_work); -out_nodev: + fcoe_interface_cleanup(fcoe); rtnl_unlock(); + fcoe_if_destroy(lport); +out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1943,25 +1854,10 @@ static int fcoe_destroy(struct net_device *netdev) static void fcoe_destroy_work(struct work_struct *work) { struct fcoe_port *port; - struct fcoe_interface *fcoe; - int npiv = 0; port = container_of(work, struct fcoe_port, destroy_work); mutex_lock(&fcoe_config_mutex); - - /* set if this is an NPIV port */ - npiv = port->lport->vport ? 1 : 0; - - fcoe = port->priv; fcoe_if_destroy(port->lport); - - /* Do not tear down the fcoe interface for NPIV port */ - if (!npiv) { - rtnl_lock(); - fcoe_interface_cleanup(fcoe); - rtnl_unlock(); - } - mutex_unlock(&fcoe_config_mutex); } @@ -1990,7 +1886,7 @@ static bool fcoe_match(struct net_device *netdev) */ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) { - int rc = 0; + int rc; struct fcoe_interface *fcoe; struct fc_lport *lport; @@ -2015,7 +1911,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) netdev->name); rc = -EIO; fcoe_interface_cleanup(fcoe); - goto out_nodev; + goto out_free; } /* Make this the "master" N_Port */ @@ -2030,6 +1926,17 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) if (!fcoe_link_ok(lport)) fcoe_ctlr_link_up(&fcoe->ctlr); + /* + * Release from init in fcoe_interface_create(), on success lport + * should be holding a reference taken in fcoe_if_create(). + */ + fcoe_interface_put(fcoe); + rtnl_unlock(); + mutex_unlock(&fcoe_config_mutex); + + return 0; +out_free: + fcoe_interface_put(fcoe); out_nodev: rtnl_unlock(); mutex_unlock(&fcoe_config_mutex); @@ -2311,6 +2218,7 @@ static void __exit fcoe_exit(void) list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) { list_del(&fcoe->list); port = lport_priv(fcoe->ctlr.lp); + fcoe_interface_cleanup(fcoe); queue_work(fcoe_wq, &port->destroy_work); } rtnl_unlock(); diff --git a/trunk/drivers/scsi/fnic/fnic.h b/trunk/drivers/scsi/fnic/fnic.h index 95a5ba29320d..671cde9d4060 100644 --- a/trunk/drivers/scsi/fnic/fnic.h +++ b/trunk/drivers/scsi/fnic/fnic.h @@ -37,7 +37,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.5.0.2" +#define DRV_VERSION "1.5.0.1" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " diff --git a/trunk/drivers/scsi/fnic/fnic_main.c b/trunk/drivers/scsi/fnic/fnic_main.c index fc98eb61e760..bb63f1a1f808 100644 --- a/trunk/drivers/scsi/fnic/fnic_main.c +++ b/trunk/drivers/scsi/fnic/fnic_main.c @@ -388,6 +388,17 @@ static void fnic_iounmap(struct fnic *fnic) iounmap(fnic->bar0.vaddr); } +/* + * Allocate element for mempools requiring GFP_DMA flag. + * Otherwise, checks in kmem_flagcheck() hit BUG_ON(). + */ +static void *fnic_alloc_slab_dma(gfp_t gfp_mask, void *pool_data) +{ + struct kmem_cache *mem = pool_data; + + return kmem_cache_alloc(mem, gfp_mask | GFP_ATOMIC | GFP_DMA); +} + /** * fnic_get_mac() - get assigned data MAC address for FIP code. * @lport: local port. @@ -592,12 +603,14 @@ static int __devinit fnic_probe(struct pci_dev *pdev, if (!fnic->io_req_pool) goto err_out_free_resources; - pool = mempool_create_slab_pool(2, fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); + pool = mempool_create(2, fnic_alloc_slab_dma, mempool_free_slab, + fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); if (!pool) goto err_out_free_ioreq_pool; fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT] = pool; - pool = mempool_create_slab_pool(2, fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); + pool = mempool_create(2, fnic_alloc_slab_dma, mempool_free_slab, + fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); if (!pool) goto err_out_free_dflt_pool; fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX] = pool; @@ -863,7 +876,7 @@ static int __init fnic_init_module(void) len = sizeof(struct fnic_dflt_sgl_list); fnic_sgl_cache[FNIC_SGL_CACHE_DFLT] = kmem_cache_create ("fnic_sgl_dflt", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN, - SLAB_HWCACHE_ALIGN, + SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, NULL); if (!fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]) { printk(KERN_ERR PFX "failed to create fnic dflt sgl slab\n"); @@ -875,7 +888,7 @@ static int __init fnic_init_module(void) len = sizeof(struct fnic_sgl_list); fnic_sgl_cache[FNIC_SGL_CACHE_MAX] = kmem_cache_create ("fnic_sgl_max", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN, - SLAB_HWCACHE_ALIGN, + SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, NULL); if (!fnic_sgl_cache[FNIC_SGL_CACHE_MAX]) { printk(KERN_ERR PFX "failed to create fnic max sgl slab\n"); diff --git a/trunk/drivers/scsi/fnic/fnic_scsi.c b/trunk/drivers/scsi/fnic/fnic_scsi.c index c40ce52ed7c6..538b31c2cf58 100644 --- a/trunk/drivers/scsi/fnic/fnic_scsi.c +++ b/trunk/drivers/scsi/fnic/fnic_scsi.c @@ -406,7 +406,7 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ if (sg_count) { io_req->sgl_list = mempool_alloc(fnic->io_sgl_pool[io_req->sgl_type], - GFP_ATOMIC); + GFP_ATOMIC | GFP_DMA); if (!io_req->sgl_list) { ret = SCSI_MLQUEUE_HOST_BUSY; scsi_dma_unmap(sc); diff --git a/trunk/drivers/scsi/iscsi_boot_sysfs.c b/trunk/drivers/scsi/iscsi_boot_sysfs.c index 89700cbca16e..df6bff7366cf 100644 --- a/trunk/drivers/scsi/iscsi_boot_sysfs.c +++ b/trunk/drivers/scsi/iscsi_boot_sysfs.c @@ -64,8 +64,7 @@ static void iscsi_boot_kobj_release(struct kobject *kobj) struct iscsi_boot_kobj *boot_kobj = container_of(kobj, struct iscsi_boot_kobj, kobj); - if (boot_kobj->release) - boot_kobj->release(boot_kobj->data); + kfree(boot_kobj->data); kfree(boot_kobj); } @@ -306,8 +305,7 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, struct attribute_group *attr_group, const char *name, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) + mode_t (*is_visible) (void *data, int type)) { struct iscsi_boot_kobj *boot_kobj; @@ -325,7 +323,6 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, boot_kobj->data = data; boot_kobj->show = show; boot_kobj->is_visible = is_visible; - boot_kobj->release = release; if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { /* @@ -334,7 +331,7 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, * the boot kobj was not setup and the normal release * path is not being run. */ - boot_kobj->release = NULL; + boot_kobj->data = NULL; kobject_put(&boot_kobj->kobj); return NULL; } @@ -360,7 +357,6 @@ static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) * @data: driver specific data for target * @show: attr show function * @is_visible: attr visibility function - * @release: release function * * Note: The boot sysfs lib will free the data passed in for the caller * when all refs to the target kobject have been released. @@ -369,12 +365,10 @@ struct iscsi_boot_kobj * iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) + mode_t (*is_visible) (void *data, int type)) { return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, - "target%d", index, data, show, is_visible, - release); + "target%d", index, data, show, is_visible); } EXPORT_SYMBOL_GPL(iscsi_boot_create_target); @@ -385,7 +379,6 @@ EXPORT_SYMBOL_GPL(iscsi_boot_create_target); * @data: driver specific data * @show: attr show function * @is_visible: attr visibility function - * @release: release function * * Note: The boot sysfs lib will free the data passed in for the caller * when all refs to the initiator kobject have been released. @@ -394,13 +387,12 @@ struct iscsi_boot_kobj * iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) + mode_t (*is_visible) (void *data, int type)) { return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_initiator_attr_group, "initiator", index, data, show, - is_visible, release); + is_visible); } EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); @@ -411,7 +403,6 @@ EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); * @data: driver specific data * @show: attr show function * @is_visible: attr visibility function - * @release: release function * * Note: The boot sysfs lib will free the data passed in for the caller * when all refs to the ethernet kobject have been released. @@ -420,13 +411,12 @@ struct iscsi_boot_kobj * iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) + mode_t (*is_visible) (void *data, int type)) { return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_ethernet_attr_group, "ethernet%d", index, data, show, - is_visible, release); + is_visible); } EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); @@ -482,9 +472,6 @@ void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) { struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; - if (!boot_kset) - return; - list_for_each_entry_safe(boot_kobj, tmp_kobj, &boot_kset->kobj_list, list) iscsi_boot_remove_kobj(boot_kobj); diff --git a/trunk/drivers/scsi/iscsi_tcp.c b/trunk/drivers/scsi/iscsi_tcp.c index 7724414588fa..3df985305f69 100644 --- a/trunk/drivers/scsi/iscsi_tcp.c +++ b/trunk/drivers/scsi/iscsi_tcp.c @@ -107,12 +107,10 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, * If the socket is in CLOSE or CLOSE_WAIT we should * not close the connection if there is still some * data pending. - * - * Must be called with sk_callback_lock. */ static inline int iscsi_sw_sk_state_check(struct sock *sk) { - struct iscsi_conn *conn = sk->sk_user_data; + struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data; if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) && !atomic_read(&sk->sk_rmem_alloc)) { @@ -125,17 +123,11 @@ static inline int iscsi_sw_sk_state_check(struct sock *sk) static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag) { - struct iscsi_conn *conn; - struct iscsi_tcp_conn *tcp_conn; + struct iscsi_conn *conn = sk->sk_user_data; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; read_descriptor_t rd_desc; read_lock(&sk->sk_callback_lock); - conn = sk->sk_user_data; - if (!conn) { - read_unlock(&sk->sk_callback_lock); - return; - } - tcp_conn = conn->dd_data; /* * Use rd_desc to pass 'conn' to iscsi_tcp_recv. @@ -149,10 +141,11 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag) iscsi_sw_sk_state_check(sk); + read_unlock(&sk->sk_callback_lock); + /* If we had to (atomically) map a highmem page, * unmap it now. */ iscsi_tcp_segment_unmap(&tcp_conn->in.segment); - read_unlock(&sk->sk_callback_lock); } static void iscsi_sw_tcp_state_change(struct sock *sk) @@ -164,11 +157,8 @@ static void iscsi_sw_tcp_state_change(struct sock *sk) void (*old_state_change)(struct sock *); read_lock(&sk->sk_callback_lock); - conn = sk->sk_user_data; - if (!conn) { - read_unlock(&sk->sk_callback_lock); - return; - } + + conn = (struct iscsi_conn*)sk->sk_user_data; session = conn->session; iscsi_sw_sk_state_check(sk); @@ -188,25 +178,11 @@ static void iscsi_sw_tcp_state_change(struct sock *sk) **/ static void iscsi_sw_tcp_write_space(struct sock *sk) { - struct iscsi_conn *conn; - struct iscsi_tcp_conn *tcp_conn; - struct iscsi_sw_tcp_conn *tcp_sw_conn; - void (*old_write_space)(struct sock *); - - read_lock_bh(&sk->sk_callback_lock); - conn = sk->sk_user_data; - if (!conn) { - read_unlock_bh(&sk->sk_callback_lock); - return; - } - - tcp_conn = conn->dd_data; - tcp_sw_conn = tcp_conn->dd_data; - old_write_space = tcp_sw_conn->old_write_space; - read_unlock_bh(&sk->sk_callback_lock); - - old_write_space(sk); + struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; + tcp_sw_conn->old_write_space(sk); ISCSI_SW_TCP_DBG(conn, "iscsi_write_space\n"); iscsi_conn_queue_work(conn); } @@ -616,17 +592,20 @@ static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) /* userspace may have goofed up and not bound us */ if (!sock) return; + /* + * Make sure our recv side is stopped. + * Older tools called conn stop before ep_disconnect + * so IO could still be coming in. + */ + write_lock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); + write_unlock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock); sock->sk->sk_err = EIO; wake_up_interruptible(sk_sleep(sock->sk)); - /* stop xmit side */ - iscsi_suspend_tx(conn); - - /* stop recv side and release socket */ - iscsi_sw_tcp_release_conn(conn); - iscsi_conn_stop(cls_conn, flag); + iscsi_sw_tcp_release_conn(conn); } static int diff --git a/trunk/drivers/scsi/libfc/fc_exch.c b/trunk/drivers/scsi/libfc/fc_exch.c index f5a0665b6773..3b8a6451ea28 100644 --- a/trunk/drivers/scsi/libfc/fc_exch.c +++ b/trunk/drivers/scsi/libfc/fc_exch.c @@ -965,30 +965,8 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, sp = &ep->seq; if (sp->id != fh->fh_seq_id) { atomic_inc(&mp->stats.seq_not_found); - if (f_ctl & FC_FC_END_SEQ) { - /* - * Update sequence_id based on incoming last - * frame of sequence exchange. This is needed - * for FCoE target where DDP has been used - * on target where, stack is indicated only - * about last frame's (payload _header) header. - * Whereas "seq_id" which is part of - * frame_header is allocated by initiator - * which is totally different from "seq_id" - * allocated when XFER_RDY was sent by target. - * To avoid false -ve which results into not - * sending RSP, hence write request on other - * end never finishes. - */ - spin_lock_bh(&ep->ex_lock); - sp->ssb_stat |= SSB_ST_RESP; - sp->id = fh->fh_seq_id; - spin_unlock_bh(&ep->ex_lock); - } else { - /* sequence/exch should exist */ - reject = FC_RJT_SEQ_ID; - goto rel; - } + reject = FC_RJT_SEQ_ID; /* sequence/exch should exist */ + goto rel; } } WARN_ON(ep != fc_seq_exch(sp)); diff --git a/trunk/drivers/scsi/libfc/fc_lport.c b/trunk/drivers/scsi/libfc/fc_lport.c index e008b1673507..389ab80aef0a 100644 --- a/trunk/drivers/scsi/libfc/fc_lport.c +++ b/trunk/drivers/scsi/libfc/fc_lport.c @@ -1025,8 +1025,6 @@ static void fc_lport_enter_reset(struct fc_lport *lport) fc_vport_set_state(lport->vport, FC_VPORT_LINKDOWN); } fc_lport_state_enter(lport, LPORT_ST_RESET); - fc_host_post_event(lport->host, fc_get_event_number(), - FCH_EVT_LIPRESET, 0); fc_vports_linkchange(lport); fc_lport_reset_locked(lport); if (lport->link_up) diff --git a/trunk/drivers/scsi/libfc/fc_rport.c b/trunk/drivers/scsi/libfc/fc_rport.c index 760db7619446..01e13a2eb93a 100644 --- a/trunk/drivers/scsi/libfc/fc_rport.c +++ b/trunk/drivers/scsi/libfc/fc_rport.c @@ -789,20 +789,6 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, switch (rdata->rp_state) { case RPORT_ST_INIT: - /* - * If received the FLOGI request on RPORT which is INIT state - * (means not transition to FLOGI either fc_rport timeout - * function didn;t trigger or this end hasn;t received - * beacon yet from other end. In that case only, allow RPORT - * state machine to continue, otherwise fall through which - * causes the code to send reject response. - * NOTE; Not checking for FIP->state such as VNMP_UP or - * VNMP_CLAIM because if FIP state is not one of those, - * RPORT wouldn;t have created and 'rport_lookup' would have - * failed anyway in that case. - */ - if (lport->point_to_multipoint) - break; case RPORT_ST_DELETE: mutex_unlock(&rdata->rp_mutex); rjt_data.reason = ELS_RJT_FIP; diff --git a/trunk/drivers/scsi/libiscsi.c b/trunk/drivers/scsi/libiscsi.c index d7a4120034a2..0c550d5b9133 100644 --- a/trunk/drivers/scsi/libiscsi.c +++ b/trunk/drivers/scsi/libiscsi.c @@ -169,7 +169,7 @@ void iscsi_prep_data_out_pdu(struct iscsi_task *task, struct iscsi_r2t_info *r2t hdr->datasn = cpu_to_be32(r2t->datasn); r2t->datasn++; hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; - hdr->lun = task->lun; + memcpy(hdr->lun, task->lun, sizeof(hdr->lun)); hdr->itt = task->hdr_itt; hdr->exp_statsn = r2t->exp_statsn; hdr->offset = cpu_to_be32(r2t->data_offset + r2t->sent); @@ -296,7 +296,7 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode) /* * Allow PDUs for unrelated LUNs */ - hdr_lun = scsilun_to_int(&tmf->lun); + hdr_lun = scsilun_to_int((struct scsi_lun *)tmf->lun); if (hdr_lun != task->sc->device->lun) return 0; /* fall through */ @@ -389,8 +389,8 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) return rc; hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->flags = ISCSI_ATTR_SIMPLE; - int_to_scsilun(sc->device->lun, &hdr->lun); - task->lun = hdr->lun; + int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); + memcpy(task->lun, hdr->lun, sizeof(task->lun)); hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); cmd_len = sc->cmd_len; if (cmd_len < ISCSI_CDB_SIZE) @@ -968,7 +968,7 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) hdr.flags = ISCSI_FLAG_CMD_FINAL; if (rhdr) { - hdr.lun = rhdr->lun; + memcpy(hdr.lun, rhdr->lun, 8); hdr.ttt = rhdr->ttt; hdr.itt = RESERVED_ITT; } else @@ -2092,7 +2092,7 @@ static void iscsi_prep_abort_task_pdu(struct iscsi_task *task, hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; hdr->flags |= ISCSI_FLAG_CMD_FINAL; - hdr->lun = task->lun; + memcpy(hdr->lun, task->lun, sizeof(hdr->lun)); hdr->rtt = task->hdr_itt; hdr->refcmdsn = task->cmdsn; } @@ -2233,7 +2233,7 @@ static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK; hdr->flags |= ISCSI_FLAG_CMD_FINAL; - int_to_scsilun(sc->device->lun, &hdr->lun); + int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); hdr->rtt = RESERVED_ITT; } diff --git a/trunk/drivers/scsi/libiscsi_tcp.c b/trunk/drivers/scsi/libiscsi_tcp.c index 09b232fd9a1b..e98ae33f1295 100644 --- a/trunk/drivers/scsi/libiscsi_tcp.c +++ b/trunk/drivers/scsi/libiscsi_tcp.c @@ -1084,8 +1084,7 @@ iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size, struct iscsi_cls_conn *cls_conn; struct iscsi_tcp_conn *tcp_conn; - cls_conn = iscsi_conn_setup(cls_session, - sizeof(*tcp_conn) + dd_data_size, conn_idx); + cls_conn = iscsi_conn_setup(cls_session, sizeof(*tcp_conn), conn_idx); if (!cls_conn) return NULL; conn = cls_conn->dd_data; @@ -1097,13 +1096,22 @@ iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size, tcp_conn = conn->dd_data; tcp_conn->iscsi_conn = conn; - tcp_conn->dd_data = conn->dd_data + sizeof(*tcp_conn); + + tcp_conn->dd_data = kzalloc(dd_data_size, GFP_KERNEL); + if (!tcp_conn->dd_data) { + iscsi_conn_teardown(cls_conn); + return NULL; + } return cls_conn; } EXPORT_SYMBOL_GPL(iscsi_tcp_conn_setup); void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn) { + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + + kfree(tcp_conn->dd_data); iscsi_conn_teardown(cls_conn); } EXPORT_SYMBOL_GPL(iscsi_tcp_conn_teardown); diff --git a/trunk/drivers/scsi/lpfc/lpfc_debugfs.c b/trunk/drivers/scsi/lpfc/lpfc_debugfs.c index 30b25c5fdd7e..ffe82d169b40 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/trunk/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1147,8 +1147,7 @@ static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes, { char mybuf[64]; char *pbuf, *step_str; - int i; - size_t bsize; + int bsize, i; /* Protect copy from user */ if (!access_ok(VERIFY_READ, buf, nbytes)) diff --git a/trunk/drivers/scsi/mac_scsi.c b/trunk/drivers/scsi/mac_scsi.c index af3a6af97cc7..bf2a1c516293 100644 --- a/trunk/drivers/scsi/mac_scsi.c +++ b/trunk/drivers/scsi/mac_scsi.c @@ -214,6 +214,13 @@ static int __init mac_scsi_setup(char *str) { __setup("mac5380=", mac_scsi_setup); +/* + * If you want to find the instance with (k)gdb ... + */ +#if NDEBUG +static struct Scsi_Host *default_instance; +#endif + /* * Function : int macscsi_detect(struct scsi_host_template * tpnt) * @@ -226,7 +233,7 @@ __setup("mac5380=", mac_scsi_setup); * */ -int __init macscsi_detect(struct scsi_host_template * tpnt) +int macscsi_detect(struct scsi_host_template * tpnt) { static int called = 0; int flags = 0; @@ -261,7 +268,10 @@ int __init macscsi_detect(struct scsi_host_template * tpnt) /* Once we support multiple 5380s (e.g. DuoDock) we'll do something different here */ instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - +#if NDEBUG + default_instance = instance; +#endif + if (macintosh_config->ident == MAC_MODEL_IIFX) { mac_scsi_regp = via1+0x8000; mac_scsi_drq = via1+0xE000; diff --git a/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h b/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h index 3105d5e8d908..a3e60385787f 100644 --- a/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.18 + * mpi2.h Version: 02.00.17 * * Version History * --------------- @@ -64,8 +64,6 @@ * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. * Added alternative defines for the SGE Direction bit. * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. - * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. * -------------------------------------------------------------------------- */ @@ -91,7 +89,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x12) +#define MPI2_HEADER_VERSION_UNIT (0x11) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -1062,14 +1060,10 @@ typedef struct _MPI2_IEEE_SGE_UNION #define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) #define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) - /* IEEE Simple Element only */ #define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) - /* IEEE Simple Element only */ #define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) #define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR (0x03) - /* IEEE Chain Element only */ + /**************************************************************************** * IEEE SGE operation Macros diff --git a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index 61475a6480e3..f5b9c766e28f 100644 --- a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.17 + * mpi2_cnfg.h Version: 02.00.16 * * Version History * --------------- @@ -127,13 +127,6 @@ * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) * defines. - * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to - * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for - * the Pinout field. - * Added BoardTemperature and BoardTemperatureUnits fields - * to MPI2_CONFIG_PAGE_IO_UNIT_7. - * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define - * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. * -------------------------------------------------------------------------- */ @@ -217,7 +210,6 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) #define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) #define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) -#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A) /***************************************************************************** @@ -620,31 +612,23 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO U32 Pinout; /* 0x00 */ U8 Connector[16]; /* 0x04 */ U8 Location; /* 0x14 */ - U8 ReceptacleID; /* 0x15 */ + U8 Reserved1; /* 0x15 */ U16 Slot; /* 0x16 */ U32 Reserved2; /* 0x18 */ } MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO, Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t; /* defines for the Pinout field */ -#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00) -#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8) - -#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF) -#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00) -#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01) -#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02) -#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03) -#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04) -#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05) -#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06) -#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07) -#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08) -#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C) -#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L4 (0x00080000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L3 (0x00040000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L2 (0x00020000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L1 (0x00010000) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L4 (0x00000800) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L3 (0x00000400) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L2 (0x00000200) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L1 (0x00000100) +#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x00000002) +#define MPI2_MANPAGE7_PINOUT_CONNECTION_UNKNOWN (0x00000001) /* defines for the Location field */ #define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) @@ -678,7 +662,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7, Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t; -#define MPI2_MANUFACTURING7_PAGEVERSION (0x01) +#define MPI2_MANUFACTURING7_PAGEVERSION (0x00) /* defines for the Flags field */ #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) @@ -865,13 +849,11 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { U16 IOCTemperature; /* 0x10 */ U8 IOCTemperatureUnits; /* 0x12 */ U8 IOCSpeed; /* 0x13 */ - U16 BoardTemperature; /* 0x14 */ - U8 BoardTemperatureUnits; /* 0x16 */ - U8 Reserved3; /* 0x17 */ + U32 Reserved3; /* 0x14 */ } MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; -#define MPI2_IOUNITPAGE7_PAGEVERSION (0x02) +#define MPI2_IOUNITPAGE7_PAGEVERSION (0x01) /* defines for IO Unit Page 7 PCIeWidth field */ #define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) @@ -899,6 +881,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { #define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) #define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) + /* defines for IO Unit Page 7 IOCTemperatureUnits field */ #define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) #define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) @@ -910,11 +893,6 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { #define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) #define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) -/* defines for IO Unit Page 7 BoardTemperatureUnits field */ -#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01) -#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02) - /**************************************************************************** @@ -2821,25 +2799,5 @@ typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 { #define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) -/**************************************************************************** -* Extended Manufacturing Config Pages -****************************************************************************/ - -/* - * Generic structure to use for product-specific extended manufacturing pages - * (currently Extended Manufacturing Page 40 through Extended Manufacturing - * Page 60). - */ - -typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 ProductSpecificInfo; /* 0x08 */ -} MPI2_CONFIG_PAGE_EXT_MAN_PS, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS, - Mpi2ExtManufacturingPagePS_t, - MPI2_POINTER pMpi2ExtManufacturingPagePS_t; - -/* PageVersion should be provided by product-specific code */ - #endif diff --git a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_init.h index de90162413c2..165454d52591 100644 --- a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -6,7 +6,7 @@ * Title: MPI SCSI initiator mode messages and structures * Creation Date: June 23, 2006 * - * mpi2_init.h Version: 02.00.11 + * mpi2_init.h Version: 02.00.10 * * Version History * --------------- @@ -33,7 +33,6 @@ * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. - * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. * -------------------------------------------------------------------------- */ @@ -140,9 +139,6 @@ typedef struct _MPI2_SCSI_IO_REQUEST #define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4) #define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0) -/* number of SGLOffset fields */ -#define MPI2_SCSIIO_NUM_SGLOFFSETS (4) - /* SCSI IO IoFlags bits */ /* Large CDB Address Space */ diff --git a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 1f0c190d336e..761cbdb8a033 100644 --- a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.16 + * mpi2_ioc.h Version: 02.00.15 * * Version History * --------------- @@ -103,7 +103,6 @@ * defines. * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. - * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. * -------------------------------------------------------------------------- */ @@ -1033,7 +1032,6 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST #define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) #define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) #define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) -#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0) /* FWDownload TransactionContext Element */ typedef struct _MPI2_FW_DOWNLOAD_TCSGE diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c index 83035bd1c489..efa0255491c2 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -94,7 +94,7 @@ module_param(diag_buffer_enable, int, 0); MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); -static int mpt2sas_fwfault_debug; +int mpt2sas_fwfault_debug; MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " "and halt firmware - (default=0)"); @@ -857,7 +857,7 @@ _base_interrupt(int irq, void *bus_id) completed_cmds = 0; cb_idx = 0xFF; do { - rd.word = le64_to_cpu(rpf->Words); + rd.word = rpf->Words; if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) goto out; reply = 0; @@ -906,7 +906,7 @@ _base_interrupt(int irq, void *bus_id) next: - rpf->Words = cpu_to_le64(ULLONG_MAX); + rpf->Words = ULLONG_MAX; ioc->reply_post_host_index = (ioc->reply_post_host_index == (ioc->reply_post_queue_depth - 1)) ? 0 : ioc->reply_post_host_index + 1; @@ -1740,11 +1740,9 @@ _base_display_dell_branding(struct MPT2SAS_ADAPTER *ioc) static void _base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) { - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) - return; + if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_INTEL && + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008) { - switch (ioc->pdev->device) { - case MPI2_MFGPAGE_DEVID_SAS2008: switch (ioc->pdev->subsystem_device) { case MPT2SAS_INTEL_RMS2LL080_SSDID: printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, @@ -1754,20 +1752,7 @@ _base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, MPT2SAS_INTEL_RMS2LL040_BRANDING); break; - default: - break; - } - case MPI2_MFGPAGE_DEVID_SAS2308_2: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_INTEL_RS25GB008_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RS25GB008_BRANDING); - break; - default: - break; } - default: - break; } } @@ -1832,9 +1817,7 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) char desc[16]; u8 revision; u32 iounit_pg1_flags; - u32 bios_version; - bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision); strncpy(desc, ioc->manu_pg0.ChipName, 16); printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), " @@ -1845,10 +1828,10 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, ioc->facts.FWVersion.Word & 0x000000FF, revision, - (bios_version & 0xFF000000) >> 24, - (bios_version & 0x00FF0000) >> 16, - (bios_version & 0x0000FF00) >> 8, - bios_version & 0x000000FF); + (ioc->bios_pg3.BiosVersion & 0xFF000000) >> 24, + (ioc->bios_pg3.BiosVersion & 0x00FF0000) >> 16, + (ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8, + ioc->bios_pg3.BiosVersion & 0x000000FF); _base_display_dell_branding(ioc); _base_display_intel_branding(ioc); @@ -2167,7 +2150,7 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) static int _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { - struct mpt2sas_facts *facts; + Mpi2IOCFactsReply_t *facts; u32 queue_size, queue_diff; u16 max_sge_elements; u16 num_of_reply_frames; @@ -2800,7 +2783,7 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes, int i; u8 failed; u16 dummy; - __le32 *mfp; + u32 *mfp; /* make sure doorbell is not in use */ if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { @@ -2888,7 +2871,7 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes, writel(0, &ioc->chip->HostInterruptStatus); if (ioc->logging_level & MPT_DEBUG_INIT) { - mfp = (__le32 *)reply; + mfp = (u32 *)reply; printk(KERN_INFO "\toffset:data\n"); for (i = 0; i < reply_bytes/4; i++) printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, @@ -3114,8 +3097,7 @@ static int _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag) { Mpi2PortFactsRequest_t mpi_request; - Mpi2PortFactsReply_t mpi_reply; - struct mpt2sas_port_facts *pfacts; + Mpi2PortFactsReply_t mpi_reply, *pfacts; int mpi_reply_sz, mpi_request_sz, r; dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, @@ -3157,8 +3139,7 @@ static int _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { Mpi2IOCFactsRequest_t mpi_request; - Mpi2IOCFactsReply_t mpi_reply; - struct mpt2sas_facts *facts; + Mpi2IOCFactsReply_t mpi_reply, *facts; int mpi_reply_sz, mpi_request_sz, r; dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, @@ -3244,6 +3225,17 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION); mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); + /* In MPI Revision I (0xA), the SystemReplyFrameSize(offset 0x18) was + * removed and made reserved. For those with older firmware will need + * this fix. It was decided that the Reply and Request frame sizes are + * the same. + */ + if ((ioc->facts.HeaderVersion >> 8) < 0xA) { + mpi_request.Reserved7 = cpu_to_le16(ioc->reply_sz); +/* mpi_request.SystemReplyFrameSize = + * cpu_to_le16(ioc->reply_sz); + */ + } mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4); mpi_request.ReplyDescriptorPostQueueDepth = @@ -3251,17 +3243,25 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) mpi_request.ReplyFreeQueueDepth = cpu_to_le16(ioc->reply_free_queue_depth); +#if BITS_PER_LONG > 32 mpi_request.SenseBufferAddressHigh = - cpu_to_le32((u64)ioc->sense_dma >> 32); + cpu_to_le32(ioc->sense_dma >> 32); mpi_request.SystemReplyAddressHigh = - cpu_to_le32((u64)ioc->reply_dma >> 32); + cpu_to_le32(ioc->reply_dma >> 32); mpi_request.SystemRequestFrameBaseAddress = - cpu_to_le64((u64)ioc->request_dma); + cpu_to_le64(ioc->request_dma); mpi_request.ReplyFreeQueueAddress = - cpu_to_le64((u64)ioc->reply_free_dma); + cpu_to_le64(ioc->reply_free_dma); mpi_request.ReplyDescriptorPostQueueAddress = - cpu_to_le64((u64)ioc->reply_post_free_dma); - + cpu_to_le64(ioc->reply_post_free_dma); +#else + mpi_request.SystemRequestFrameBaseAddress = + cpu_to_le32(ioc->request_dma); + mpi_request.ReplyFreeQueueAddress = + cpu_to_le32(ioc->reply_free_dma); + mpi_request.ReplyDescriptorPostQueueAddress = + cpu_to_le32(ioc->reply_post_free_dma); +#endif /* This time stamp specifies number of milliseconds * since epoch ~ midnight January 1, 1970. @@ -3271,10 +3271,10 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) (current_time.tv_usec / 1000)); if (ioc->logging_level & MPT_DEBUG_INIT) { - __le32 *mfp; + u32 *mfp; int i; - mfp = (__le32 *)&mpi_request; + mfp = (u32 *)&mpi_request; printk(KERN_INFO "\toffset:data\n"); for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, @@ -3759,7 +3759,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) /* initialize Reply Post Free Queue */ for (i = 0; i < ioc->reply_post_queue_depth; i++) - ioc->reply_post_free[i].Words = cpu_to_le64(ULLONG_MAX); + ioc->reply_post_free[i].Words = ULLONG_MAX; r = _base_send_ioc_init(ioc, sleep_flag); if (r) diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h index 8d5be2120c63..dcc289c25459 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,11 +69,11 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "09.100.00.00" -#define MPT2SAS_MAJOR_VERSION 09 +#define MPT2SAS_DRIVER_VERSION "08.100.00.02" +#define MPT2SAS_MAJOR_VERSION 08 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 00 -#define MPT2SAS_RELEASE_VERSION 00 +#define MPT2SAS_RELEASE_VERSION 02 /* * Set MPT2SAS_SG_DEPTH value based on user input. @@ -161,15 +161,12 @@ "Intel Integrated RAID Module RMS2LL080" #define MPT2SAS_INTEL_RMS2LL040_BRANDING \ "Intel Integrated RAID Module RMS2LL040" -#define MPT2SAS_INTEL_RS25GB008_BRANDING \ - "Intel(R) RAID Controller RS25GB008" /* * Intel HBA SSDIDs */ #define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E #define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F -#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000 /* @@ -544,63 +541,6 @@ struct _tr_list { typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); -/* IOC Facts and Port Facts converted from little endian to cpu */ -union mpi2_version_union { - MPI2_VERSION_STRUCT Struct; - u32 Word; -}; - -struct mpt2sas_facts { - u16 MsgVersion; - u16 HeaderVersion; - u8 IOCNumber; - u8 VP_ID; - u8 VF_ID; - u16 IOCExceptions; - u16 IOCStatus; - u32 IOCLogInfo; - u8 MaxChainDepth; - u8 WhoInit; - u8 NumberOfPorts; - u8 MaxMSIxVectors; - u16 RequestCredit; - u16 ProductID; - u32 IOCCapabilities; - union mpi2_version_union FWVersion; - u16 IOCRequestFrameSize; - u16 Reserved3; - u16 MaxInitiators; - u16 MaxTargets; - u16 MaxSasExpanders; - u16 MaxEnclosures; - u16 ProtocolFlags; - u16 HighPriorityCredit; - u16 MaxReplyDescriptorPostQueueDepth; - u8 ReplyFrameSize; - u8 MaxVolumes; - u16 MaxDevHandle; - u16 MaxPersistentEntries; - u16 MinDevHandle; -}; - -struct mpt2sas_port_facts { - u8 PortNumber; - u8 VP_ID; - u8 VF_ID; - u8 PortType; - u16 MaxPostedCmdBuffers; -}; - -/** - * enum mutex_type - task management mutex type - * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it - * @TM_MUTEX_ON: mutex is required - */ -enum mutex_type { - TM_MUTEX_OFF = 0, - TM_MUTEX_ON = 1, -}; - /** * struct MPT2SAS_ADAPTER - per adapter struct * @list: ioc_list @@ -763,7 +703,6 @@ struct MPT2SAS_ADAPTER { /* misc flags */ int aen_event_read_flag; u8 broadcast_aen_busy; - u16 broadcast_aen_pending; u8 shost_recovery; struct mutex reset_in_progress_mutex; @@ -810,8 +749,8 @@ struct MPT2SAS_ADAPTER { u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; /* static config pages */ - struct mpt2sas_facts facts; - struct mpt2sas_port_facts *pfacts; + Mpi2IOCFactsReply_t facts; + Mpi2PortFactsReply_t *pfacts; Mpi2ManufacturingPage0_t manu_pg0; Mpi2BiosPage2_t bios_pg2; Mpi2BiosPage3_t bios_pg3; @@ -901,7 +840,7 @@ struct MPT2SAS_ADAPTER { /* reply free queue */ u16 reply_free_queue_depth; - __le32 *reply_free; + u32 *reply_free; dma_addr_t reply_free_dma; struct dma_pool *reply_free_dma_pool; u32 reply_free_host_index; @@ -993,8 +932,8 @@ void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply); int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, - uint channel, uint id, uint lun, u8 type, u16 smid_task, - ulong timeout, unsigned long serial_number, enum mutex_type m_type); + uint channel, uint id, uint lun, u8 type, u16 smid_task, + ulong timeout, struct scsi_cmnd *scmd); void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 38ed0260959d..437c2d94c45a 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -994,7 +994,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, mpt2sas_scsih_issue_tm(ioc, le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10, - 0, TM_MUTEX_ON); + NULL); ioc->tm_cmds.status = MPT2_CMD_NOT_USED; } else mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, @@ -2706,13 +2706,13 @@ static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL); struct DIAG_BUFFER_START { - __le32 Size; - __le32 DiagVersion; + u32 Size; + u32 DiagVersion; u8 BufferType; u8 Reserved[3]; - __le32 Reserved1; - __le32 Reserved2; - __le32 Reserved3; + u32 Reserved1; + u32 Reserved2; + u32 Reserved3; }; /** * _ctl_host_trace_buffer_size_show - host buffer size (trace only) diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_debug.h b/trunk/drivers/scsi/mpt2sas/mpt2sas_debug.h index 9731f8e661bf..3dcddfeb6f4c 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_debug.h @@ -164,7 +164,7 @@ static inline void _debug_dump_mf(void *mpi_request, int sz) { int i; - __le32 *mfp = (__le32 *)mpi_request; + u32 *mfp = (u32 *)mpi_request; printk(KERN_INFO "mf:\n\t"); for (i = 0; i < sz; i++) { diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 939f283d0c28..a7dbc6825f5f 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -94,10 +94,6 @@ static u32 logging_level; MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info " "(default=0)"); -static ushort max_sectors = 0xFFFF; -module_param(max_sectors, ushort, 0); -MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 8192 default=8192"); - /* scsi-mid layer global parmeter is max_report_luns, which is 511 */ #define MPT2SAS_MAX_LUN (16895) static int max_lun = MPT2SAS_MAX_LUN; @@ -1960,7 +1956,7 @@ _scsih_slave_configure(struct scsi_device *sdev) case MPI2_RAID_VOL_TYPE_RAID1E: qdepth = MPT2SAS_RAID_QUEUE_DEPTH; if (ioc->manu_pg10.OEMIdentifier && - (le32_to_cpu(ioc->manu_pg10.GenericFlags0) & + (ioc->manu_pg10.GenericFlags0 & MFG10_GF0_R10_DISPLAY) && !(raid_device->num_pds % 2)) r_level = "RAID10"; @@ -2240,8 +2236,6 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) * @smid_task: smid assigned to the task * @timeout: timeout in seconds - * @serial_number: the serial_number from scmd - * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF * Context: user * * A generic API for sending task management requests to firmware. @@ -2253,18 +2247,17 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, uint id, uint lun, u8 type, u16 smid_task, ulong timeout, - unsigned long serial_number, enum mutex_type m_type) + struct scsi_cmnd *scmd) { Mpi2SCSITaskManagementRequest_t *mpi_request; Mpi2SCSITaskManagementReply_t *mpi_reply; u16 smid = 0; u32 ioc_state; unsigned long timeleft; - struct scsiio_tracker *scsi_lookup = NULL; + struct scsi_cmnd *scmd_lookup; int rc; - if (m_type == TM_MUTEX_ON) - mutex_lock(&ioc->tm_cmds.mutex); + mutex_lock(&ioc->tm_cmds.mutex); if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) { printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n", __func__, ioc->name); @@ -2284,18 +2277,18 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, if (ioc_state & MPI2_DOORBELL_USED) { dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " "active!\n", ioc->name)); - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; + rc = SUCCESS; goto err_out; } if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { mpt2sas_base_fault_info(ioc, ioc_state & MPI2_DOORBELL_DATA_MASK); - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; + rc = SUCCESS; goto err_out; } @@ -2307,9 +2300,6 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, goto err_out; } - if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) - scsi_lookup = &ioc->scsi_lookup[smid_task - 1]; - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, smid_task)); @@ -2317,7 +2307,6 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); ioc->tm_cmds.smid = smid; memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); - memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t)); mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; mpi_request->DevHandle = cpu_to_le16(handle); mpi_request->TaskType = type; @@ -2333,9 +2322,9 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, _debug_dump_mf(mpi_request, sizeof(Mpi2SCSITaskManagementRequest_t)/4); if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) { - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; + rc = SUCCESS; ioc->tm_cmds.status = MPT2_CMD_NOT_USED; mpt2sas_scsih_clear_tm_flag(ioc, handle); goto err_out; @@ -2357,12 +2346,20 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, } } + /* sanity check: + * Check to see the commands were terminated. + * This is only needed for eh callbacks, hence the scmd check. + */ + rc = FAILED; + if (scmd == NULL) + goto bypass_sanity_checks; switch (type) { case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: - rc = SUCCESS; - if (scsi_lookup->scmd == NULL) - break; - rc = FAILED; + scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task); + if (scmd_lookup) + rc = FAILED; + else + rc = SUCCESS; break; case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: @@ -2372,31 +2369,24 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, rc = SUCCESS; break; - case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) rc = FAILED; else rc = SUCCESS; break; - case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: - rc = SUCCESS; - break; - default: - rc = FAILED; - break; } + bypass_sanity_checks: + mpt2sas_scsih_clear_tm_flag(ioc, handle); ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - if (m_type == TM_MUTEX_ON) - mutex_unlock(&ioc->tm_cmds.mutex); + mutex_unlock(&ioc->tm_cmds.mutex); return rc; err_out: - if (m_type == TM_MUTEX_ON) - mutex_unlock(&ioc->tm_cmds.mutex); + mutex_unlock(&ioc->tm_cmds.mutex); return rc; } @@ -2506,8 +2496,7 @@ _scsih_abort(struct scsi_cmnd *scmd) handle = sas_device_priv_data->sas_target->handle; r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, scmd->device->id, scmd->device->lun, - MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, - scmd->serial_number, TM_MUTEX_ON); + MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd); out: sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", @@ -2568,8 +2557,7 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, scmd->device->id, scmd->device->lun, - MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, 0, - TM_MUTEX_ON); + MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd); out: sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", @@ -2629,7 +2617,7 @@ _scsih_target_reset(struct scsi_cmnd *scmd) r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, - 30, 0, TM_MUTEX_ON); + 30, scmd); out: starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", @@ -2761,31 +2749,6 @@ _scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc) } } -/** - * _scsih_ublock_io_all_device - unblock every device - * @ioc: per adapter object - * - * change the device state from block to running - */ -static void -_scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (!sas_device_priv_data->block) - continue; - sas_device_priv_data->block = 0; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, " - "handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); - scsi_internal_device_unblock(sdev); - } -} /** * _scsih_ublock_io_device - set the device state to SDEV_RUNNING * @ioc: per adapter object @@ -2815,34 +2778,6 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) } } -/** - * _scsih_block_io_all_device - set the device state to SDEV_BLOCK - * @ioc: per adapter object - * @handle: device handle - * - * During device pull we need to appropiately set the sdev state. - */ -static void -_scsih_block_io_all_device(struct MPT2SAS_ADAPTER *ioc) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (sas_device_priv_data->block) - continue; - sas_device_priv_data->block = 1; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_blocked, " - "handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); - scsi_internal_device_block(sdev); - } -} - - /** * _scsih_block_io_device - set the device state to SDEV_BLOCK * @ioc: per adapter object @@ -3763,7 +3698,7 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) return 0; } - if (ioc->pci_error_recovery || ioc->remove_host) { + if (ioc->pci_error_recovery) { scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); return 0; @@ -4663,7 +4598,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) Mpi2SasEnclosurePage0_t enclosure_pg0; u32 ioc_status; u16 parent_handle; - u64 sas_address, sas_address_parent = 0; + __le64 sas_address, sas_address_parent = 0; int i; unsigned long flags; struct _sas_port *mpt2sas_port = NULL; @@ -5445,10 +5380,9 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, break; } printk(MPT2SAS_INFO_FMT "device status change: (%s)\n" - "\thandle(0x%04x), sas address(0x%016llx), tag(%d)", - ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), - (unsigned long long)le64_to_cpu(event_data->SASAddress), - le16_to_cpu(event_data->TaskTag)); + "\thandle(0x%04x), sas address(0x%016llx)", ioc->name, + reason_str, le16_to_cpu(event_data->DevHandle), + (unsigned long long)le64_to_cpu(event_data->SASAddress)); if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, event_data->ASC, event_data->ASCQ); @@ -5470,7 +5404,7 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, { struct MPT2SAS_TARGET *target_priv_data; struct _sas_device *sas_device; - u64 sas_address; + __le64 sas_address; unsigned long flags; Mpi2EventDataSasDeviceStatusChange_t *event_data = fw_event->event_data; @@ -5588,38 +5522,25 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u32 termination_count; u32 query_count; Mpi2SCSITaskManagementReply_t *mpi_reply; +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data; +#endif u16 ioc_status; unsigned long flags; int r; - u8 max_retries = 0; - u8 task_abort_retries; - mutex_lock(&ioc->tm_cmds.mutex); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: phy number(%d), " - "width(%d)\n", ioc->name, __func__, event_data->PhyNum, - event_data->PortWidth)); - - _scsih_block_io_all_device(ioc); + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primitive: " + "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum, + event_data->PortWidth)); + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, + __func__)); spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - mpi_reply = ioc->tm_cmds.reply; -broadcast_aen_retry: - - /* sanity checks for retrying this loop */ - if (max_retries++ == 5) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: giving up\n", - ioc->name, __func__)); - goto out; - } else if (max_retries > 1) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %d retry\n", - ioc->name, __func__, max_retries - 1)); - + ioc->broadcast_aen_busy = 0; termination_count = 0; query_count = 0; + mpi_reply = ioc->tm_cmds.reply; for (smid = 1; smid <= ioc->scsiio_depth; smid++) { - if (ioc->ioc_reset_in_progress_status) - goto out; scmd = _scsih_scsi_lookup_get(ioc, smid); if (!scmd) continue; @@ -5640,90 +5561,34 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, lun = sas_device_priv_data->lun; query_count++; - if (ioc->ioc_reset_in_progress_status) - goto out; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, - MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, 0, - TM_MUTEX_OFF); - if (r == FAILED) { - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: FAILED when sending " - "QUERY_TASK: scmd(%p)\n", scmd); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } + mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, + MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL); + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - sdev_printk(KERN_WARNING, sdev, "query task: FAILED " - "with IOCSTATUS(0x%04x), scmd(%p)\n", ioc_status, - scmd); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - - /* see if IO is still owned by IOC and target */ - if (mpi_reply->ResponseCode == + if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) && + (mpi_reply->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || mpi_reply->ResponseCode == - MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) { + MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) { spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); continue; } - task_abort_retries = 0; - tm_retry: - if (task_abort_retries++ == 60) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: ABORT_TASK: giving up\n", ioc->name, - __func__)); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - - if (ioc->ioc_reset_in_progress_status) - goto out_no_lock; - r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id, sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, - scmd->serial_number, TM_MUTEX_OFF); - if (r == FAILED) { - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : " + scmd); + if (r == FAILED) + sdev_printk(KERN_WARNING, sdev, "task abort: FAILED " "scmd(%p)\n", scmd); - goto tm_retry; - } - - if (task_abort_retries > 1) - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):" - " scmd(%p)\n", - task_abort_retries - 1, scmd); - termination_count += le32_to_cpu(mpi_reply->TerminationCount); spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); } - - if (ioc->broadcast_aen_pending) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: loop back due to" - " pending AEN\n", ioc->name, __func__)); - ioc->broadcast_aen_pending = 0; - goto broadcast_aen_retry; - } - - out: spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - out_no_lock: - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - exit, query_count = %d termination_count = %d\n", ioc->name, __func__, query_count, termination_count)); - - ioc->broadcast_aen_busy = 0; - if (!ioc->ioc_reset_in_progress_status) - _scsih_ublock_io_all_device(ioc); - mutex_unlock(&ioc->tm_cmds.mutex); } /** @@ -6701,7 +6566,7 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc) Mpi2ExpanderPage0_t expander_pg0; Mpi2ConfigReply_t mpi_reply; u16 ioc_status; - u64 sas_address; + __le64 sas_address; u16 handle; printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); @@ -6997,14 +6862,10 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, mpi_reply->EventData; if (baen_data->Primitive != - MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) + MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT || + ioc->broadcast_aen_busy) return 1; - - if (ioc->broadcast_aen_busy) { - ioc->broadcast_aen_pending++; - return 1; - } else - ioc->broadcast_aen_busy = 1; + ioc->broadcast_aen_busy = 1; break; } @@ -7350,6 +7211,7 @@ _scsih_remove(struct pci_dev *pdev) } sas_remove_host(shost); + _scsih_shutdown(pdev); list_del(&ioc->list); scsi_remove_host(shost); scsi_host_put(shost); @@ -7574,25 +7436,6 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) shost->transportt = mpt2sas_transport_template; shost->unique_id = ioc->id; - if (max_sectors != 0xFFFF) { - if (max_sectors < 64) { - shost->max_sectors = 64; - printk(MPT2SAS_WARN_FMT "Invalid value %d passed " - "for max_sectors, range is 64 to 8192. Assigning " - "value of 64.\n", ioc->name, max_sectors); - } else if (max_sectors > 8192) { - shost->max_sectors = 8192; - printk(MPT2SAS_WARN_FMT "Invalid value %d passed " - "for max_sectors, range is 64 to 8192. Assigning " - "default value of 8192.\n", ioc->name, - max_sectors); - } else { - shost->max_sectors = max_sectors & 0xFFFE; - printk(MPT2SAS_INFO_FMT "The max_sectors value is " - "set to %d\n", ioc->name, shost->max_sectors); - } - } - if ((scsi_add_host(shost, &pdev->dev))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); @@ -7662,7 +7505,7 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - pci_power_t device_state; + u32 device_state; mpt2sas_base_stop_watchdog(ioc); scsi_block_requests(shost); @@ -7689,7 +7532,7 @@ _scsih_resume(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - pci_power_t device_state = pdev->current_state; + u32 device_state = pdev->current_state; int r; printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous " diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c index 15c798026217..cb1cdecbe0f8 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -299,6 +299,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, void *data_out = NULL; dma_addr_t data_out_dma; u32 sz; + u64 *sas_address_le; u16 wait_state_count; if (ioc->shost_recovery || ioc->pci_error_recovery) { @@ -371,7 +372,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, mpi_request->PhysicalPort = 0xFF; mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(sas_address); + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(sas_address); mpi_request->RequestDataLength = cpu_to_le16(sizeof(struct rep_manu_request)); psge = &mpi_request->SGL; @@ -1047,14 +1049,14 @@ struct phy_error_log_reply{ u8 function; /* 0x11 */ u8 function_result; u8 response_length; - __be16 expander_change_count; + u16 expander_change_count; u8 reserved_1[3]; u8 phy_identifier; u8 reserved_2[2]; - __be32 invalid_dword; - __be32 running_disparity_error; - __be32 loss_of_dword_sync; - __be32 phy_reset_problem; + u32 invalid_dword; + u32 running_disparity_error; + u32 loss_of_dword_sync; + u32 phy_reset_problem; }; /** @@ -1083,6 +1085,7 @@ _transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, void *data_out = NULL; dma_addr_t data_out_dma; u32 sz; + u64 *sas_address_le; u16 wait_state_count; if (ioc->shost_recovery || ioc->pci_error_recovery) { @@ -1157,7 +1160,8 @@ _transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, mpi_request->PhysicalPort = 0xFF; mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(phy->identify.sas_address); mpi_request->RequestDataLength = cpu_to_le16(sizeof(struct phy_error_log_request)); psge = &mpi_request->SGL; @@ -1402,6 +1406,7 @@ _transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc, void *data_out = NULL; dma_addr_t data_out_dma; u32 sz; + u64 *sas_address_le; u16 wait_state_count; if (ioc->shost_recovery) { @@ -1481,7 +1486,8 @@ _transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc, mpi_request->PhysicalPort = 0xFF; mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(phy->identify.sas_address); mpi_request->RequestDataLength = cpu_to_le16(sizeof(struct phy_error_log_request)); psge = &mpi_request->SGL; @@ -1908,7 +1914,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, mpi_request->PhysicalPort = 0xFF; mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - mpi_request->SASAddress = (rphy) ? + *((u64 *)&mpi_request->SASAddress) = (rphy) ? cpu_to_le64(rphy->identify.sas_address) : cpu_to_le64(ioc->sas_hba.sas_address); mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); diff --git a/trunk/drivers/scsi/scsi_devinfo.c b/trunk/drivers/scsi/scsi_devinfo.c index cf8dfab9489f..82e9e5c0476e 100644 --- a/trunk/drivers/scsi/scsi_devinfo.c +++ b/trunk/drivers/scsi/scsi_devinfo.c @@ -197,7 +197,6 @@ static struct { {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"IBM", "2105", NULL, BLIST_RETRY_HWERROR}, {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, - {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN}, {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, {"INSITE", "I325VM", NULL, BLIST_KEY}, @@ -244,7 +243,6 @@ static struct { {"Tornado-", "F4", "*", BLIST_NOREPORTLUN}, {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, - {"Traxdata", "CDR4120", NULL, BLIST_NOLUN}, /* locks up */ {"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36}, {"WangDAT", "Model 2600", "01.7", BLIST_SELECT_NO_ATN}, {"WangDAT", "Model 3200", "02.2", BLIST_SELECT_NO_ATN}, diff --git a/trunk/drivers/scsi/scsi_lib.c b/trunk/drivers/scsi/scsi_lib.c index 28d9c9d6b4b4..ec1803a48723 100644 --- a/trunk/drivers/scsi/scsi_lib.c +++ b/trunk/drivers/scsi/scsi_lib.c @@ -213,8 +213,6 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int ret = DRIVER_ERROR << 24; req = blk_get_request(sdev->request_queue, write, __GFP_WAIT); - if (!req) - return ret; if (bufflen && blk_rq_map_kern(sdev->request_queue, req, buffer, bufflen, __GFP_WAIT)) diff --git a/trunk/drivers/scsi/ses.c b/trunk/drivers/scsi/ses.c index eba183c428cf..eb7a3e85304f 100644 --- a/trunk/drivers/scsi/ses.c +++ b/trunk/drivers/scsi/ses.c @@ -160,10 +160,6 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev, return NULL; } -/* For device slot and array device slot elements, byte 3 bit 6 - * is "fault sensed" while byte 3 bit 5 is "fault reqstd". As this - * code stands these bits are shifted 4 positions right so in - * sysfs they will appear as bits 2 and 1 respectively. Strange. */ static void ses_get_fault(struct enclosure_device *edev, struct enclosure_component *ecomp) { @@ -185,7 +181,7 @@ static int ses_set_fault(struct enclosure_device *edev, /* zero is disabled */ break; case ENCLOSURE_SETTING_ENABLED: - desc[3] = 0x20; + desc[2] = 0x02; break; default: /* SES doesn't do the SGPIO blink settings */ diff --git a/trunk/drivers/scsi/sr.c b/trunk/drivers/scsi/sr.c index 5fc97d2ba2fd..4778e2707168 100644 --- a/trunk/drivers/scsi/sr.c +++ b/trunk/drivers/scsi/sr.c @@ -221,33 +221,14 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi, return 0; events = sr_get_events(cd->device); - cd->get_event_changed |= events & DISK_EVENT_MEDIA_CHANGE; - - /* - * If earlier GET_EVENT_STATUS_NOTIFICATION and TUR did not agree - * for several times in a row. We rely on TUR only for this likely - * broken device, to prevent generating incorrect media changed - * events for every open(). - */ - if (cd->ignore_get_event) { - events &= ~DISK_EVENT_MEDIA_CHANGE; - goto do_tur; - } - /* * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE * is being cleared. Note that there are devices which hang * if asked to execute TUR repeatedly. */ - if (cd->device->changed) { - events |= DISK_EVENT_MEDIA_CHANGE; - cd->device->changed = 0; - cd->tur_changed = true; - } - if (!(clearing & DISK_EVENT_MEDIA_CHANGE)) - return events; -do_tur: + goto skip_tur; + /* let's see whether the media is there with TUR */ last_present = cd->media_present; ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); @@ -261,31 +242,12 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi, (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a); if (last_present != cd->media_present) - cd->device->changed = 1; - + events |= DISK_EVENT_MEDIA_CHANGE; +skip_tur: if (cd->device->changed) { events |= DISK_EVENT_MEDIA_CHANGE; cd->device->changed = 0; - cd->tur_changed = true; - } - - if (cd->ignore_get_event) - return events; - - /* check whether GET_EVENT is reporting spurious MEDIA_CHANGE */ - if (!cd->tur_changed) { - if (cd->get_event_changed) { - if (cd->tur_mismatch++ > 8) { - sdev_printk(KERN_WARNING, cd->device, - "GET_EVENT and TUR disagree continuously, suppress GET_EVENT events\n"); - cd->ignore_get_event = true; - } - } else { - cd->tur_mismatch = 0; - } } - cd->tur_changed = false; - cd->get_event_changed = false; return events; } diff --git a/trunk/drivers/scsi/sr.h b/trunk/drivers/scsi/sr.h index 37c8f6b17510..e036f1dc83c8 100644 --- a/trunk/drivers/scsi/sr.h +++ b/trunk/drivers/scsi/sr.h @@ -41,13 +41,6 @@ typedef struct scsi_cd { unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ unsigned readcd_cdda:1; /* reading audio data using READ_CD */ unsigned media_present:1; /* media is present */ - - /* GET_EVENT spurious event handling, blk layer guarantees exclusion */ - int tur_mismatch; /* nr of get_event TUR mismatches */ - bool tur_changed:1; /* changed according to TUR */ - bool get_event_changed:1; /* changed according to GET_EVENT */ - bool ignore_get_event:1; /* GET_EVENT is unreliable, use TUR */ - struct cdrom_device_info cdi; /* We hold gendisk and scsi_device references on probe and use * the refs on this kref to decide when to release them */ diff --git a/trunk/drivers/scsi/sun3_NCR5380.c b/trunk/drivers/scsi/sun3_NCR5380.c index 7e12a2e4e0a3..07eaef1c722b 100644 --- a/trunk/drivers/scsi/sun3_NCR5380.c +++ b/trunk/drivers/scsi/sun3_NCR5380.c @@ -49,6 +49,13 @@ * inside the execution of NCR5380_intr(), leading to recursive * calls. * + * - I've added a function merge_contiguous_buffers() that tries to + * merge scatter-gather buffers that are located at contiguous + * physical addresses and can be processed with the same DMA setup. + * Since most scatter-gather operations work on a page (4K) of + * 4 buffers (1K), in more than 90% of all cases three interrupts and + * DMA setup actions are saved. + * * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA * and USLEEP, because these were messing up readability and will never be * needed for Atari SCSI. @@ -259,9 +266,8 @@ static struct scsi_host_template *the_template = NULL; (struct NCR5380_hostdata *)(in)->hostdata #define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) -#define NEXT(cmd) ((struct scsi_cmnd *)(cmd)->host_scribble) -#define SET_NEXT(cmd, next) ((cmd)->host_scribble = (void *)(next)) -#define NEXTADDR(cmd) ((struct scsi_cmnd **)&((cmd)->host_scribble)) +#define NEXT(cmd) (*(struct scsi_cmnd **)&((cmd)->host_scribble)) +#define NEXTADDR(cmd) ((struct scsi_cmnd **)&((cmd)->host_scribble)) #define HOSTNO instance->host_no #define H_NO(cmd) (cmd)->device->host->host_no @@ -452,6 +458,47 @@ static void free_all_tags( void ) #endif /* SUPPORT_TAGS */ +/* + * Function: void merge_contiguous_buffers(struct scsi_cmnd *cmd) + * + * Purpose: Try to merge several scatter-gather requests into one DMA + * transfer. This is possible if the scatter buffers lie on + * physical contiguous addresses. + * + * Parameters: struct scsi_cmnd *cmd + * The command to work on. The first scatter buffer's data are + * assumed to be already transferred into ptr/this_residual. + */ + +static void merge_contiguous_buffers(struct scsi_cmnd *cmd) +{ + unsigned long endaddr; +#if (NDEBUG & NDEBUG_MERGING) + unsigned long oldlen = cmd->SCp.this_residual; + int cnt = 1; +#endif + + for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; + cmd->SCp.buffers_residual && + virt_to_phys(SGADDR(&(cmd->SCp.buffer[1]))) == endaddr; ) { + + MER_PRINTK("VTOP(%p) == %08lx -> merging\n", + SGADDR(&(cmd->SCp.buffer[1])), endaddr); +#if (NDEBUG & NDEBUG_MERGING) + ++cnt; +#endif + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual += cmd->SCp.buffer->length; + endaddr += cmd->SCp.buffer->length; + } +#if (NDEBUG & NDEBUG_MERGING) + if (oldlen != cmd->SCp.this_residual) + MER_PRINTK("merged %d buffers from %p, new length %08x\n", + cnt, cmd->SCp.ptr, cmd->SCp.this_residual); +#endif +} + /* * Function : void initialize_SCp(struct scsi_cmnd *cmd) * @@ -473,6 +520,11 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd) cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; + + /* ++roman: Try to merge some scatter-buffers if they are at + * contiguous physical addresses. + */ +// merge_contiguous_buffers( cmd ); } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; @@ -789,7 +841,7 @@ static char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer, * */ -static int __init NCR5380_init(struct Scsi_Host *instance, int flags) +static int NCR5380_init (struct Scsi_Host *instance, int flags) { int i; SETUP_HOSTDATA(instance); @@ -837,11 +889,6 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags) return 0; } -static void NCR5380_exit(struct Scsi_Host *instance) -{ - /* Empty, as we didn't schedule any delayed work */ -} - /* * Function : int NCR5380_queue_command (struct scsi_cmnd *cmd, * void (*done)(struct scsi_cmnd *)) @@ -915,7 +962,7 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, * in a queue */ - SET_NEXT(cmd, NULL); + NEXT(cmd) = NULL; cmd->scsi_done = done; cmd->result = 0; @@ -943,14 +990,14 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, */ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { LIST(cmd, hostdata->issue_queue); - SET_NEXT(cmd, hostdata->issue_queue); + NEXT(cmd) = hostdata->issue_queue; hostdata->issue_queue = cmd; } else { for (tmp = (struct scsi_cmnd *)hostdata->issue_queue; NEXT(tmp); tmp = NEXT(tmp)) ; LIST(cmd, tmp); - SET_NEXT(tmp, cmd); + NEXT(tmp) = cmd; } local_irq_restore(flags); @@ -1058,12 +1105,12 @@ static void NCR5380_main (struct work_struct *bl) local_irq_disable(); if (prev) { REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - SET_NEXT(prev, NEXT(tmp)); + NEXT(prev) = NEXT(tmp); } else { REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); hostdata->issue_queue = NEXT(tmp); } - SET_NEXT(tmp, NULL); + NEXT(tmp) = NULL; /* reenable interrupts after finding one */ local_irq_restore(flags); @@ -1097,7 +1144,7 @@ static void NCR5380_main (struct work_struct *bl) } else { local_irq_disable(); LIST(tmp, hostdata->issue_queue); - SET_NEXT(tmp, hostdata->issue_queue); + NEXT(tmp) = hostdata->issue_queue; hostdata->issue_queue = tmp; #ifdef SUPPORT_TAGS cmd_free_tag( tmp ); @@ -1392,7 +1439,7 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd, local_irq_restore(flags); /* Wait for arbitration logic to complete */ -#ifdef NCR_TIMEOUT +#if NCR_TIMEOUT { unsigned long timeout = jiffies + 2*NCR_TIMEOUT; @@ -2023,6 +2070,11 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) --cmd->SCp.buffers_residual; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = SGADDR(cmd->SCp.buffer); + + /* ++roman: Try to merge some scatter-buffers if + * they are at contiguous physical addresses. + */ +// merge_contiguous_buffers( cmd ); INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", HOSTNO, cmd->SCp.this_residual, cmd->SCp.buffers_residual); @@ -2222,7 +2274,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) local_irq_save(flags); LIST(cmd,hostdata->issue_queue); - SET_NEXT(cmd, hostdata->issue_queue); + NEXT(cmd) = hostdata->issue_queue; hostdata->issue_queue = (struct scsi_cmnd *) cmd; local_irq_restore(flags); QU_PRINTK("scsi%d: REQUEST SENSE added to head of " @@ -2278,7 +2330,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) local_irq_save(flags); cmd->device->disconnect = 1; LIST(cmd,hostdata->disconnected_queue); - SET_NEXT(cmd, hostdata->disconnected_queue); + NEXT(cmd) = hostdata->disconnected_queue; hostdata->connected = NULL; hostdata->disconnected_queue = cmd; local_irq_restore(flags); @@ -2537,12 +2589,12 @@ static void NCR5380_reselect (struct Scsi_Host *instance) ) { if (prev) { REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - SET_NEXT(prev, NEXT(tmp)); + NEXT(prev) = NEXT(tmp); } else { REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); hostdata->disconnected_queue = NEXT(tmp); } - SET_NEXT(tmp, NULL); + NEXT(tmp) = NULL; break; } } @@ -2710,7 +2762,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) if (cmd == tmp) { REMOVE(5, *prev, tmp, NEXT(tmp)); (*prev) = NEXT(tmp); - SET_NEXT(tmp, NULL); + NEXT(tmp) = NULL; tmp->result = DID_ABORT << 16; local_irq_restore(flags); ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", @@ -2783,7 +2835,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) if (cmd == tmp) { REMOVE(5, *prev, tmp, NEXT(tmp)); *prev = NEXT(tmp); - SET_NEXT(tmp, NULL); + NEXT(tmp) = NULL; tmp->result = DID_ABORT << 16; /* We must unlock the tag/LUN immediately here, since the * target goes to BUS FREE and doesn't send us another @@ -2891,7 +2943,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) for (i = 0; (cmd = disconnected_queue); ++i) { disconnected_queue = NEXT(cmd); - SET_NEXT(cmd, NULL); + NEXT(cmd) = NULL; cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); cmd->scsi_done( cmd ); } diff --git a/trunk/drivers/scsi/sun3_scsi.c b/trunk/drivers/scsi/sun3_scsi.c index baf7328de956..613f5880d135 100644 --- a/trunk/drivers/scsi/sun3_scsi.c +++ b/trunk/drivers/scsi/sun3_scsi.c @@ -70,12 +70,6 @@ #include #include -#define NDEBUG 0 - -#define NDEBUG_ABORT 0x00100000 -#define NDEBUG_TAGS 0x00200000 -#define NDEBUG_MERGING 0x00400000 - /* dma on! */ #define REAL_DMA @@ -92,6 +86,8 @@ static void NCR5380_print(struct Scsi_Host *instance); /*#define RESET_BOOT */ #define DRIVER_SETUP +#define NDEBUG 0 + /* * BUG can be used to trigger a strange code-size related hang on 2.1 kernels */ @@ -199,7 +195,7 @@ static struct Scsi_Host *default_instance; * */ -int __init sun3scsi_detect(struct scsi_host_template * tpnt) +int sun3scsi_detect(struct scsi_host_template * tpnt) { unsigned long ioaddr; static int called = 0; @@ -318,7 +314,6 @@ int sun3scsi_release (struct Scsi_Host *shpnt) iounmap((void *)sun3_scsi_regp); - NCR5380_exit(shpnt); return 0; } diff --git a/trunk/drivers/scsi/sun3_scsi_vme.c b/trunk/drivers/scsi/sun3_scsi_vme.c index fbba78e5722e..7c526b8e30ac 100644 --- a/trunk/drivers/scsi/sun3_scsi_vme.c +++ b/trunk/drivers/scsi/sun3_scsi_vme.c @@ -39,12 +39,6 @@ /* dma on! */ #define REAL_DMA -#define NDEBUG 0 - -#define NDEBUG_ABORT 0x00100000 -#define NDEBUG_TAGS 0x00200000 -#define NDEBUG_MERGING 0x00400000 - #include "scsi.h" #include "initio.h" #include @@ -56,6 +50,8 @@ extern int sun3_map_test(unsigned long, char *); /*#define RESET_BOOT */ #define DRIVER_SETUP +#define NDEBUG 0 + /* * BUG can be used to trigger a strange code-size related hang on 2.1 kernels */ @@ -141,7 +137,7 @@ static struct Scsi_Host *default_instance; * */ -static int __init sun3scsi_detect(struct scsi_host_template * tpnt) +static int sun3scsi_detect(struct scsi_host_template * tpnt) { unsigned long ioaddr, irq = 0; static int called = 0; @@ -287,7 +283,6 @@ int sun3scsi_release (struct Scsi_Host *shpnt) iounmap((void *)sun3_scsi_regp); - NCR5380_exit(shpnt); return 0; } diff --git a/trunk/drivers/sh/clk/core.c b/trunk/drivers/sh/clk/core.c index d6702e57d428..7e9c39951ecb 100644 --- a/trunk/drivers/sh/clk/core.c +++ b/trunk/drivers/sh/clk/core.c @@ -670,7 +670,7 @@ static struct dentry *clk_debugfs_root; static int clk_debugfs_register_one(struct clk *c) { int err; - struct dentry *d; + struct dentry *d, *child, *child_tmp; struct clk *pa = c->parent; char s[255]; char *p = s; @@ -699,7 +699,10 @@ static int clk_debugfs_register_one(struct clk *c) return 0; err_out: - debugfs_remove_recursive(c->dentry); + d = c->dentry; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(c->dentry); return err; } diff --git a/trunk/drivers/staging/pohmelfs/dir.c b/trunk/drivers/staging/pohmelfs/dir.c index 7598e77672a5..9732a9666cc4 100644 --- a/trunk/drivers/staging/pohmelfs/dir.c +++ b/trunk/drivers/staging/pohmelfs/dir.c @@ -512,7 +512,7 @@ struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct int err, lock_type = POHMELFS_READ_LOCK, need_lock = 1; struct qstr str = dentry->d_name; - if ((nd->intent.open.flags & O_ACCMODE) != O_RDONLY) + if ((nd->intent.open.flags & O_ACCMODE) > 1) lock_type = POHMELFS_WRITE_LOCK; if (test_bit(NETFS_INODE_OWNED, &parent->state)) { diff --git a/trunk/drivers/staging/pohmelfs/inode.c b/trunk/drivers/staging/pohmelfs/inode.c index f3c6060c96b8..c0f0ac7c1cdb 100644 --- a/trunk/drivers/staging/pohmelfs/inode.c +++ b/trunk/drivers/staging/pohmelfs/inode.c @@ -887,16 +887,11 @@ static struct inode *pohmelfs_alloc_inode(struct super_block *sb) /* * We want fsync() to work on POHMELFS. */ -static int pohmelfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int pohmelfs_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; - int err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (!err) { - mutex_lock(&inode->i_mutex); - err = sync_inode_metadata(inode, 1); - mutex_unlock(&inode->i_mutex); - } - return err; + + return sync_inode_metadata(inode, 1); } ssize_t pohmelfs_write(struct file *file, const char __user *buf, diff --git a/trunk/drivers/target/tcm_fc/tfc_cmd.c b/trunk/drivers/target/tcm_fc/tfc_cmd.c index a6bfb6deba94..a9e9a31da11d 100644 --- a/trunk/drivers/target/tcm_fc/tfc_cmd.c +++ b/trunk/drivers/target/tcm_fc/tfc_cmd.c @@ -264,9 +264,8 @@ int ft_write_pending(struct se_cmd *se_cmd) cmd->sg_cnt = se_cmd->t_tasks_sg_chained_no; } - if (cmd->sg && lport->tt.ddp_target(lport, ep->xid, - cmd->sg, - cmd->sg_cnt)) + if (cmd->sg && lport->tt.ddp_setup(lport, ep->xid, + cmd->sg, cmd->sg_cnt)) cmd->was_ddp_setup = 1; } } @@ -372,23 +371,12 @@ static void ft_send_resp_status(struct fc_lport *lport, /* * Send error or task management response. + * Always frees the cmd and associated state. */ -static void ft_send_resp_code(struct ft_cmd *cmd, - enum fcp_resp_rsp_codes code) +static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) { ft_send_resp_status(cmd->sess->tport->lport, cmd->req_frame, SAM_STAT_GOOD, code); -} - - -/* - * Send error or task management response. - * Always frees the cmd and associated state. - */ -static void ft_send_resp_code_and_free(struct ft_cmd *cmd, - enum fcp_resp_rsp_codes code) -{ - ft_send_resp_code(cmd, code); ft_free_cmd(cmd); } @@ -426,7 +414,7 @@ static void ft_send_tm(struct ft_cmd *cmd) * tm_flags set is invalid. */ pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); - ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); + ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); return; } @@ -434,7 +422,7 @@ static void ft_send_tm(struct ft_cmd *cmd) tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); if (!tmr) { pr_debug("alloc failed\n"); - ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED); + ft_send_resp_code(cmd, FCP_TMF_FAILED); return; } cmd->se_cmd.se_tmr_req = tmr; @@ -673,7 +661,7 @@ static void ft_send_cmd(struct ft_cmd *cmd) return; err: - ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); + ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); } /* diff --git a/trunk/drivers/usb/gadget/printer.c b/trunk/drivers/usb/gadget/printer.c index 978e6a101bf2..271ef94668e7 100644 --- a/trunk/drivers/usb/gadget/printer.c +++ b/trunk/drivers/usb/gadget/printer.c @@ -795,14 +795,12 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) } static int -printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) +printer_fsync(struct file *fd, int datasync) { struct printer_dev *dev = fd->private_data; - struct inode *inode = fd->f_path.dentry->d_inode; unsigned long flags; int tx_list_empty; - mutex_lock(&inode->i_mutex); spin_lock_irqsave(&dev->lock, flags); tx_list_empty = (likely(list_empty(&dev->tx_reqs))); spin_unlock_irqrestore(&dev->lock, flags); @@ -812,7 +810,6 @@ printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) wait_event_interruptible(dev->tx_flush_wait, (likely(list_empty(&dev->tx_reqs_active)))); } - mutex_unlock(&inode->i_mutex); return 0; } diff --git a/trunk/drivers/video/fb_defio.c b/trunk/drivers/video/fb_defio.c index 32814e8800e0..804000183c5e 100644 --- a/trunk/drivers/video/fb_defio.c +++ b/trunk/drivers/video/fb_defio.c @@ -66,26 +66,19 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma, return 0; } -int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int fb_deferred_io_fsync(struct file *file, int datasync) { struct fb_info *info = file->private_data; - struct inode *inode = file->f_path.dentry->d_inode; - int err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; /* Skip if deferred io is compiled-in but disabled on this fbdev */ if (!info->fbdefio) return 0; - mutex_lock(&inode->i_mutex); /* Kill off the delayed work */ cancel_delayed_work_sync(&info->deferred_work); /* Run it immediately */ - err = schedule_delayed_work(&info->deferred_work, 0); - mutex_unlock(&inode->i_mutex); - return err; + return schedule_delayed_work(&info->deferred_work, 0); } EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); diff --git a/trunk/drivers/virtio/Kconfig b/trunk/drivers/virtio/Kconfig index 57e493b1bd20..3dd6294d10b6 100644 --- a/trunk/drivers/virtio/Kconfig +++ b/trunk/drivers/virtio/Kconfig @@ -7,8 +7,6 @@ config VIRTIO_RING tristate depends on VIRTIO -menu "Virtio drivers" - config VIRTIO_PCI tristate "PCI driver for virtio devices (EXPERIMENTAL)" depends on PCI && EXPERIMENTAL @@ -35,4 +33,3 @@ config VIRTIO_BALLOON If unsure, say M. -endmenu diff --git a/trunk/fs/9p/acl.c b/trunk/fs/9p/acl.c index e98f56d3787d..535ab6eccb1a 100644 --- a/trunk/fs/9p/acl.c +++ b/trunk/fs/9p/acl.c @@ -96,12 +96,12 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type) return acl; } -int v9fs_check_acl(struct inode *inode, int mask) +int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; struct v9fs_session_info *v9ses; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; v9ses = v9fs_inode2v9ses(inode); diff --git a/trunk/fs/9p/acl.h b/trunk/fs/9p/acl.h index 59e18c2e8c7e..7ef3ac9f6d95 100644 --- a/trunk/fs/9p/acl.h +++ b/trunk/fs/9p/acl.h @@ -16,7 +16,7 @@ #ifdef CONFIG_9P_FS_POSIX_ACL extern int v9fs_get_acl(struct inode *, struct p9_fid *); -extern int v9fs_check_acl(struct inode *inode, int mask); +extern int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags); extern int v9fs_acl_chmod(struct dentry *); extern int v9fs_set_create_acl(struct dentry *, struct posix_acl *, struct posix_acl *); diff --git a/trunk/fs/9p/cache.c b/trunk/fs/9p/cache.c index 945aa5f02f9b..5b335c5086a1 100644 --- a/trunk/fs/9p/cache.c +++ b/trunk/fs/9p/cache.c @@ -108,10 +108,11 @@ static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data, void *buffer, uint16_t bufmax) { const struct v9fs_inode *v9inode = cookie_netfs_data; - memcpy(buffer, &v9inode->qid.path, sizeof(v9inode->qid.path)); + memcpy(buffer, &v9inode->fscache_key->path, + sizeof(v9inode->fscache_key->path)); P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &v9inode->vfs_inode, - v9inode->qid.path); - return sizeof(v9inode->qid.path); + v9inode->fscache_key->path); + return sizeof(v9inode->fscache_key->path); } static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data, @@ -128,10 +129,11 @@ static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data, void *buffer, uint16_t buflen) { const struct v9fs_inode *v9inode = cookie_netfs_data; - memcpy(buffer, &v9inode->qid.version, sizeof(v9inode->qid.version)); + memcpy(buffer, &v9inode->fscache_key->version, + sizeof(v9inode->fscache_key->version)); P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &v9inode->vfs_inode, - v9inode->qid.version); - return sizeof(v9inode->qid.version); + v9inode->fscache_key->version); + return sizeof(v9inode->fscache_key->version); } static enum @@ -141,11 +143,11 @@ fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data, { const struct v9fs_inode *v9inode = cookie_netfs_data; - if (buflen != sizeof(v9inode->qid.version)) + if (buflen != sizeof(v9inode->fscache_key->version)) return FSCACHE_CHECKAUX_OBSOLETE; - if (memcmp(buffer, &v9inode->qid.version, - sizeof(v9inode->qid.version))) + if (memcmp(buffer, &v9inode->fscache_key->version, + sizeof(v9inode->fscache_key->version))) return FSCACHE_CHECKAUX_OBSOLETE; return FSCACHE_CHECKAUX_OKAY; diff --git a/trunk/fs/9p/cache.h b/trunk/fs/9p/cache.h index 40cc54ced5d9..049507a5b01c 100644 --- a/trunk/fs/9p/cache.h +++ b/trunk/fs/9p/cache.h @@ -93,6 +93,15 @@ static inline void v9fs_uncache_page(struct inode *inode, struct page *page) BUG_ON(PageFsCache(page)); } +static inline void v9fs_fscache_set_key(struct inode *inode, + struct p9_qid *qid) +{ + struct v9fs_inode *v9inode = V9FS_I(inode); + spin_lock(&v9inode->fscache_lock); + v9inode->fscache_key = qid; + spin_unlock(&v9inode->fscache_lock); +} + static inline void v9fs_fscache_wait_on_page_write(struct inode *inode, struct page *page) { diff --git a/trunk/fs/9p/v9fs.c b/trunk/fs/9p/v9fs.c index ef9661886112..c82b017f51f3 100644 --- a/trunk/fs/9p/v9fs.c +++ b/trunk/fs/9p/v9fs.c @@ -78,25 +78,6 @@ static const match_table_t tokens = { {Opt_err, NULL} }; -/* Interpret mount options for cache mode */ -static int get_cache_mode(char *s) -{ - int version = -EINVAL; - - if (!strcmp(s, "loose")) { - version = CACHE_LOOSE; - P9_DPRINTK(P9_DEBUG_9P, "Cache mode: loose\n"); - } else if (!strcmp(s, "fscache")) { - version = CACHE_FSCACHE; - P9_DPRINTK(P9_DEBUG_9P, "Cache mode: fscache\n"); - } else if (!strcmp(s, "none")) { - version = CACHE_NONE; - P9_DPRINTK(P9_DEBUG_9P, "Cache mode: none\n"); - } else - printk(KERN_INFO "9p: Unknown Cache mode %s.\n", s); - return version; -} - /** * v9fs_parse_options - parse mount options into session structure * @v9ses: existing v9fs session information @@ -116,7 +97,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) /* setup defaults */ v9ses->afid = ~0; v9ses->debug = 0; - v9ses->cache = CACHE_NONE; + v9ses->cache = 0; #ifdef CONFIG_9P_FSCACHE v9ses->cachetag = NULL; #endif @@ -190,13 +171,13 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) "problem allocating copy of cache arg\n"); goto free_and_return; } - ret = get_cache_mode(s); - if (ret == -EINVAL) { - kfree(s); - goto free_and_return; - } - v9ses->cache = ret; + if (strcmp(s, "loose") == 0) + v9ses->cache = CACHE_LOOSE; + else if (strcmp(s, "fscache") == 0) + v9ses->cache = CACHE_FSCACHE; + else + v9ses->cache = CACHE_NONE; kfree(s); break; @@ -219,15 +200,9 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) } else { v9ses->flags |= V9FS_ACCESS_SINGLE; v9ses->uid = simple_strtoul(s, &e, 10); - if (*e != '\0') { - ret = -EINVAL; - printk(KERN_INFO "9p: Unknown access " - "argument %s.\n", s); - kfree(s); - goto free_and_return; - } + if (*e != '\0') + v9ses->uid = ~0; } - kfree(s); break; @@ -512,8 +487,8 @@ static void v9fs_inode_init_once(void *foo) struct v9fs_inode *v9inode = (struct v9fs_inode *)foo; #ifdef CONFIG_9P_FSCACHE v9inode->fscache = NULL; + v9inode->fscache_key = NULL; #endif - memset(&v9inode->qid, 0, sizeof(v9inode->qid)); inode_init_once(&v9inode->vfs_inode); } diff --git a/trunk/fs/9p/v9fs.h b/trunk/fs/9p/v9fs.h index e78956cbd702..e5ebedfc5ed8 100644 --- a/trunk/fs/9p/v9fs.h +++ b/trunk/fs/9p/v9fs.h @@ -125,8 +125,8 @@ struct v9fs_inode { #ifdef CONFIG_9P_FSCACHE spinlock_t fscache_lock; struct fscache_cookie *fscache; + struct p9_qid *fscache_key; #endif - struct p9_qid qid; unsigned int cache_validity; struct p9_fid *writeback_fid; struct mutex v_mutex; @@ -153,13 +153,13 @@ extern void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p); extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, - struct super_block *sb, int new); + struct super_block *sb); extern const struct inode_operations v9fs_dir_inode_operations_dotl; extern const struct inode_operations v9fs_file_inode_operations_dotl; extern const struct inode_operations v9fs_symlink_inode_operations_dotl; extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, - struct super_block *sb, int new); + struct super_block *sb); /* other default globals */ #define V9FS_PORT 564 @@ -201,27 +201,8 @@ v9fs_get_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, struct super_block *sb) { if (v9fs_proto_dotl(v9ses)) - return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 0); + return v9fs_inode_from_fid_dotl(v9ses, fid, sb); else - return v9fs_inode_from_fid(v9ses, fid, sb, 0); + return v9fs_inode_from_fid(v9ses, fid, sb); } - -/** - * v9fs_get_new_inode_from_fid - Helper routine to populate an inode by - * issuing a attribute request - * @v9ses: session information - * @fid: fid to issue attribute request for - * @sb: superblock on which to create inode - * - */ -static inline struct inode * -v9fs_get_new_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, - struct super_block *sb) -{ - if (v9fs_proto_dotl(v9ses)) - return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 1); - else - return v9fs_inode_from_fid(v9ses, fid, sb, 1); -} - #endif diff --git a/trunk/fs/9p/v9fs_vfs.h b/trunk/fs/9p/v9fs_vfs.h index 46ce357ca1ab..4014160903a9 100644 --- a/trunk/fs/9p/v9fs_vfs.h +++ b/trunk/fs/9p/v9fs_vfs.h @@ -70,8 +70,7 @@ ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); ssize_t v9fs_fid_readn(struct p9_fid *, char *, char __user *, u32, u64); void v9fs_blank_wstat(struct p9_wstat *wstat); int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); -int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end, - int datasync); +int v9fs_file_fsync_dotl(struct file *filp, int datasync); ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *, const char __user *, size_t, loff_t *, int); int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode); diff --git a/trunk/fs/9p/vfs_file.c b/trunk/fs/9p/vfs_file.c index 3c173fcc2c5a..ffed55817f0c 100644 --- a/trunk/fs/9p/vfs_file.c +++ b/trunk/fs/9p/vfs_file.c @@ -519,50 +519,32 @@ v9fs_file_write(struct file *filp, const char __user * data, } -static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int v9fs_file_fsync(struct file *filp, int datasync) { struct p9_fid *fid; - struct inode *inode = filp->f_mapping->host; struct p9_wstat wstat; int retval; - retval = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (retval) - return retval; - - mutex_lock(&inode->i_mutex); P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync); fid = filp->private_data; v9fs_blank_wstat(&wstat); retval = p9_client_wstat(fid, &wstat); - mutex_unlock(&inode->i_mutex); - return retval; } -int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end, - int datasync) +int v9fs_file_fsync_dotl(struct file *filp, int datasync) { struct p9_fid *fid; - struct inode *inode = filp->f_mapping->host; int retval; - retval = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (retval) - return retval; - - mutex_lock(&inode->i_mutex); P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n", filp, datasync); fid = filp->private_data; retval = p9_client_fsync(fid, datasync); - mutex_unlock(&inode->i_mutex); - return retval; } diff --git a/trunk/fs/9p/vfs_inode.c b/trunk/fs/9p/vfs_inode.c index 8bb5507e822f..7f6c67703195 100644 --- a/trunk/fs/9p/vfs_inode.c +++ b/trunk/fs/9p/vfs_inode.c @@ -216,6 +216,7 @@ struct inode *v9fs_alloc_inode(struct super_block *sb) return NULL; #ifdef CONFIG_9P_FSCACHE v9inode->fscache = NULL; + v9inode->fscache_key = NULL; spin_lock_init(&v9inode->fscache_lock); #endif v9inode->writeback_fid = NULL; @@ -432,60 +433,17 @@ void v9fs_evict_inode(struct inode *inode) } } -static int v9fs_test_inode(struct inode *inode, void *data) -{ - int umode; - struct v9fs_inode *v9inode = V9FS_I(inode); - struct p9_wstat *st = (struct p9_wstat *)data; - struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); - - umode = p9mode2unixmode(v9ses, st->mode); - /* don't match inode of different type */ - if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) - return 0; - - /* compare qid details */ - if (memcmp(&v9inode->qid.version, - &st->qid.version, sizeof(v9inode->qid.version))) - return 0; - - if (v9inode->qid.type != st->qid.type) - return 0; - return 1; -} - -static int v9fs_test_new_inode(struct inode *inode, void *data) -{ - return 0; -} - -static int v9fs_set_inode(struct inode *inode, void *data) -{ - struct v9fs_inode *v9inode = V9FS_I(inode); - struct p9_wstat *st = (struct p9_wstat *)data; - - memcpy(&v9inode->qid, &st->qid, sizeof(st->qid)); - return 0; -} - static struct inode *v9fs_qid_iget(struct super_block *sb, struct p9_qid *qid, - struct p9_wstat *st, - int new) + struct p9_wstat *st) { int retval, umode; unsigned long i_ino; struct inode *inode; struct v9fs_session_info *v9ses = sb->s_fs_info; - int (*test)(struct inode *, void *); - - if (new) - test = v9fs_test_new_inode; - else - test = v9fs_test_inode; i_ino = v9fs_qid2ino(qid); - inode = iget5_locked(sb, i_ino, test, v9fs_set_inode, st); + inode = iget_locked(sb, i_ino); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) @@ -495,7 +453,6 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, * FIXME!! we may need support for stale inodes * later. */ - inode->i_ino = i_ino; umode = p9mode2unixmode(v9ses, st->mode); retval = v9fs_init_inode(v9ses, inode, umode); if (retval) @@ -503,6 +460,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, v9fs_stat2inode(st, inode, sb); #ifdef CONFIG_9P_FSCACHE + v9fs_fscache_set_key(inode, &st->qid); v9fs_cache_inode_get_cookie(inode); #endif unlock_new_inode(inode); @@ -516,7 +474,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, struct inode * v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, - struct super_block *sb, int new) + struct super_block *sb) { struct p9_wstat *st; struct inode *inode = NULL; @@ -525,7 +483,7 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, if (IS_ERR(st)) return ERR_CAST(st); - inode = v9fs_qid_iget(sb, &st->qid, st, new); + inode = v9fs_qid_iget(sb, &st->qid, st); p9stat_free(st); kfree(st); return inode; @@ -534,50 +492,38 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, /** * v9fs_remove - helper function to remove files and directories * @dir: directory inode that is being deleted - * @dentry: dentry that is being deleted + * @file: dentry that is being deleted * @rmdir: removing a directory * */ -static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags) +static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) { - struct inode *inode; - int retval = -EOPNOTSUPP; - struct p9_fid *v9fid, *dfid; - struct v9fs_session_info *v9ses; + int retval; + struct p9_fid *v9fid; + struct inode *file_inode; - P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %x\n", - dir, dentry, flags); + P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, + rmdir); - v9ses = v9fs_inode2v9ses(dir); - inode = dentry->d_inode; - dfid = v9fs_fid_lookup(dentry->d_parent); - if (IS_ERR(dfid)) { - retval = PTR_ERR(dfid); - P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", retval); - return retval; - } - if (v9fs_proto_dotl(v9ses)) - retval = p9_client_unlinkat(dfid, dentry->d_name.name, flags); - if (retval == -EOPNOTSUPP) { - /* Try the one based on path */ - v9fid = v9fs_fid_clone(dentry); - if (IS_ERR(v9fid)) - return PTR_ERR(v9fid); - retval = p9_client_remove(v9fid); - } + file_inode = file->d_inode; + v9fid = v9fs_fid_clone(file); + if (IS_ERR(v9fid)) + return PTR_ERR(v9fid); + + retval = p9_client_remove(v9fid); if (!retval) { /* * directories on unlink should have zero * link count */ - if (flags & AT_REMOVEDIR) { - clear_nlink(inode); + if (rmdir) { + clear_nlink(file_inode); drop_nlink(dir); } else - drop_nlink(inode); + drop_nlink(file_inode); - v9fs_invalidate_inode_attr(inode); + v9fs_invalidate_inode_attr(file_inode); v9fs_invalidate_inode_attr(dir); } return retval; @@ -639,7 +585,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, } /* instantiate inode and assign the unopened fid to the dentry */ - inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); @@ -687,8 +633,8 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, fid = NULL; v9ses = v9fs_inode2v9ses(dir); perm = unixmode2p9mode(v9ses, mode); - if (nd) - flags = nd->intent.open.flags; + if (nd && nd->flags & LOOKUP_OPEN) + flags = nd->intent.open.flags - 1; else flags = O_RDWR; @@ -703,7 +649,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, v9fs_invalidate_inode_attr(dir); /* if we are opening a file, assign the open fid to the file */ - if (nd) { + if (nd && nd->flags & LOOKUP_OPEN) { v9inode = V9FS_I(dentry->d_inode); mutex_lock(&v9inode->v_mutex); if (v9ses->cache && !v9inode->writeback_fid && @@ -868,7 +814,7 @@ int v9fs_vfs_unlink(struct inode *i, struct dentry *d) int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) { - return v9fs_remove(i, d, AT_REMOVEDIR); + return v9fs_remove(i, d, 1); } /** @@ -916,12 +862,9 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, down_write(&v9ses->rename_sem); if (v9fs_proto_dotl(v9ses)) { - retval = p9_client_renameat(olddirfid, old_dentry->d_name.name, - newdirfid, new_dentry->d_name.name); - if (retval == -EOPNOTSUPP) - retval = p9_client_rename(oldfid, newdirfid, - new_dentry->d_name.name); - if (retval != -EOPNOTSUPP) + retval = p9_client_rename(oldfid, newdirfid, + (char *) new_dentry->d_name.name); + if (retval != -ENOSYS) goto clunk_newdir; } if (old_dentry->d_parent != new_dentry->d_parent) { @@ -946,6 +889,11 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, clear_nlink(new_inode); else drop_nlink(new_inode); + /* + * Work around vfs rename rehash bug with + * FS_RENAME_DOES_D_MOVE + */ + v9fs_invalidate_inode_attr(new_inode); } if (S_ISDIR(old_inode->i_mode)) { if (!new_inode) diff --git a/trunk/fs/9p/vfs_inode_dotl.c b/trunk/fs/9p/vfs_inode_dotl.c index 276f4a69ecd4..691c78f58bef 100644 --- a/trunk/fs/9p/vfs_inode_dotl.c +++ b/trunk/fs/9p/vfs_inode_dotl.c @@ -86,63 +86,18 @@ static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode) return dentry; } -static int v9fs_test_inode_dotl(struct inode *inode, void *data) -{ - struct v9fs_inode *v9inode = V9FS_I(inode); - struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; - - /* don't match inode of different type */ - if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT)) - return 0; - - if (inode->i_generation != st->st_gen) - return 0; - - /* compare qid details */ - if (memcmp(&v9inode->qid.version, - &st->qid.version, sizeof(v9inode->qid.version))) - return 0; - - if (v9inode->qid.type != st->qid.type) - return 0; - return 1; -} - -/* Always get a new inode */ -static int v9fs_test_new_inode_dotl(struct inode *inode, void *data) -{ - return 0; -} - -static int v9fs_set_inode_dotl(struct inode *inode, void *data) -{ - struct v9fs_inode *v9inode = V9FS_I(inode); - struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; - - memcpy(&v9inode->qid, &st->qid, sizeof(st->qid)); - inode->i_generation = st->st_gen; - return 0; -} - static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, struct p9_qid *qid, struct p9_fid *fid, - struct p9_stat_dotl *st, - int new) + struct p9_stat_dotl *st) { int retval; unsigned long i_ino; struct inode *inode; struct v9fs_session_info *v9ses = sb->s_fs_info; - int (*test)(struct inode *, void *); - - if (new) - test = v9fs_test_new_inode_dotl; - else - test = v9fs_test_inode_dotl; i_ino = v9fs_qid2ino(qid); - inode = iget5_locked(sb, i_ino, test, v9fs_set_inode_dotl, st); + inode = iget_locked(sb, i_ino); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) @@ -152,13 +107,13 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, * FIXME!! we may need support for stale inodes * later. */ - inode->i_ino = i_ino; retval = v9fs_init_inode(v9ses, inode, st->st_mode); if (retval) goto error; v9fs_stat2inode_dotl(st, inode); #ifdef CONFIG_9P_FSCACHE + v9fs_fscache_set_key(inode, &st->qid); v9fs_cache_inode_get_cookie(inode); #endif retval = v9fs_get_acl(inode, fid); @@ -176,16 +131,16 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, struct inode * v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, - struct super_block *sb, int new) + struct super_block *sb) { struct p9_stat_dotl *st; struct inode *inode = NULL; - st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN); + st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); if (IS_ERR(st)) return ERR_CAST(st); - inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st, new); + inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st); kfree(st); return inode; } @@ -218,8 +173,8 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, struct posix_acl *pacl = NULL, *dacl = NULL; v9ses = v9fs_inode2v9ses(dir); - if (nd) - flags = nd->intent.open.flags; + if (nd && nd->flags & LOOKUP_OPEN) + flags = nd->intent.open.flags - 1; else { /* * create call without LOOKUP_OPEN is due @@ -275,7 +230,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, fid = NULL; goto error; } - inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); @@ -395,7 +350,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, goto error; } - inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", @@ -592,7 +547,7 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) inode->i_blocks = stat->st_blocks; } if (stat->st_result_mask & P9_STATS_GEN) - inode->i_generation = stat->st_gen; + inode->i_generation = stat->st_gen; /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION * because the inode structure does not have fields for them. @@ -648,7 +603,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, } /* instantiate inode and assign the unopened fid to dentry */ - inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", @@ -801,7 +756,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, goto error; } - inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { err = PTR_ERR(inode); P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", diff --git a/trunk/fs/affs/affs.h b/trunk/fs/affs/affs.h index c2b9c79eb64e..0e95f73a7023 100644 --- a/trunk/fs/affs/affs.h +++ b/trunk/fs/affs/affs.h @@ -182,7 +182,7 @@ extern int affs_add_entry(struct inode *dir, struct inode *inode, struct dent void affs_free_prealloc(struct inode *inode); extern void affs_truncate(struct inode *); -int affs_file_fsync(struct file *, loff_t, loff_t, int); +int affs_file_fsync(struct file *, int); /* dir.c */ diff --git a/trunk/fs/affs/file.c b/trunk/fs/affs/file.c index 2f4c935cb327..acf321b70fcd 100644 --- a/trunk/fs/affs/file.c +++ b/trunk/fs/affs/file.c @@ -923,20 +923,14 @@ affs_truncate(struct inode *inode) affs_free_prealloc(inode); } -int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) +int affs_file_fsync(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; int ret, err; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - mutex_lock(&inode->i_mutex); ret = write_inode_now(inode, 0); err = sync_blockdev(inode->i_sb->s_bdev); if (!ret) ret = err; - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/afs/afs_vl.h b/trunk/fs/afs/afs_vl.h index 800f607ffaf5..8bbefe009ed4 100644 --- a/trunk/fs/afs/afs_vl.h +++ b/trunk/fs/afs/afs_vl.h @@ -49,7 +49,7 @@ enum AFSVL_Errors { AFSVL_BADVOLOPER = 363542, /* Bad volume operation code */ AFSVL_BADRELLOCKTYPE = 363543, /* Bad release lock type */ AFSVL_RERELEASE = 363544, /* Status report: last release was aborted */ - AFSVL_BADSERVERFLAG = 363545, /* Invalid replication site server flag */ + AFSVL_BADSERVERFLAG = 363545, /* Invalid replication site server °ag */ AFSVL_PERM = 363546, /* No permission access */ AFSVL_NOMEM = 363547, /* malloc/realloc failed to alloc enough memory */ }; diff --git a/trunk/fs/afs/internal.h b/trunk/fs/afs/internal.h index d2b0888126d4..5a9b6843bac1 100644 --- a/trunk/fs/afs/internal.h +++ b/trunk/fs/afs/internal.h @@ -627,7 +627,7 @@ extern void afs_clear_permits(struct afs_vnode *); extern void afs_cache_permit(struct afs_vnode *, struct key *, long); extern void afs_zap_permits(struct rcu_head *); extern struct key *afs_request_key(struct afs_cell *); -extern int afs_permission(struct inode *, int); +extern int afs_permission(struct inode *, int, unsigned int); /* * server.c @@ -750,7 +750,7 @@ extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); extern ssize_t afs_file_write(struct kiocb *, const struct iovec *, unsigned long, loff_t); extern int afs_writeback_all(struct afs_vnode *); -extern int afs_fsync(struct file *, loff_t, loff_t, int); +extern int afs_fsync(struct file *, int); /*****************************************************************************/ diff --git a/trunk/fs/afs/security.c b/trunk/fs/afs/security.c index 8d010422dc89..f44b9d355377 100644 --- a/trunk/fs/afs/security.c +++ b/trunk/fs/afs/security.c @@ -285,14 +285,14 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key, * - AFS ACLs are attached to directories only, and a file is controlled by its * parent directory's ACL */ -int afs_permission(struct inode *inode, int mask) +int afs_permission(struct inode *inode, int mask, unsigned int flags) { struct afs_vnode *vnode = AFS_FS_I(inode); afs_access_t uninitialized_var(access); struct key *key; int ret; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; _enter("{{%x:%u},%lx},%x,", @@ -350,7 +350,7 @@ int afs_permission(struct inode *inode, int mask) } key_put(key); - ret = generic_permission(inode, mask); + ret = generic_permission(inode, mask, flags, NULL); _leave(" = %d", ret); return ret; diff --git a/trunk/fs/afs/write.c b/trunk/fs/afs/write.c index 9aa52d93c73c..b806285ff853 100644 --- a/trunk/fs/afs/write.c +++ b/trunk/fs/afs/write.c @@ -681,10 +681,9 @@ int afs_writeback_all(struct afs_vnode *vnode) * - the return status from this call provides a reliable indication of * whether any write errors occurred for this process. */ -int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int afs_fsync(struct file *file, int datasync) { struct dentry *dentry = file->f_path.dentry; - struct inode *inode = file->f_mapping->host; struct afs_writeback *wb, *xwb; struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); int ret; @@ -693,19 +692,12 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name, datasync); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - /* use a writeback record as a marker in the queue - when this reaches * the front of the queue, all the outstanding writes are either * completed or rejected */ wb = kzalloc(sizeof(*wb), GFP_KERNEL); - if (!wb) { - ret = -ENOMEM; - goto out; - } + if (!wb) + return -ENOMEM; wb->vnode = vnode; wb->first = 0; wb->last = -1; @@ -728,7 +720,7 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) if (ret < 0) { afs_put_writeback(wb); _leave(" = %d [wb]", ret); - goto out; + return ret; } /* wait for the preceding writes to actually complete */ @@ -737,8 +729,6 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) vnode->writebacks.next == &wb->link); afs_put_writeback(wb); _leave(" = %d", ret); -out: - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/attr.c b/trunk/fs/attr.c index 538e27959d3f..caf2aa521e2b 100644 --- a/trunk/fs/attr.c +++ b/trunk/fs/attr.c @@ -232,11 +232,17 @@ int notify_change(struct dentry * dentry, struct iattr * attr) if (error) return error; + if (ia_valid & ATTR_SIZE) + down_write(&dentry->d_inode->i_alloc_sem); + if (inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); else error = simple_setattr(dentry, attr); + if (ia_valid & ATTR_SIZE) + up_write(&dentry->d_inode->i_alloc_sem); + if (!error) fsnotify_change(dentry, ia_valid); diff --git a/trunk/fs/bad_inode.c b/trunk/fs/bad_inode.c index 9205cf25f1c6..bfcb18feb1df 100644 --- a/trunk/fs/bad_inode.c +++ b/trunk/fs/bad_inode.c @@ -87,8 +87,7 @@ static int bad_file_release(struct inode *inode, struct file *filp) return -EIO; } -static int bad_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int bad_file_fsync(struct file *file, int datasync) { return -EIO; } @@ -230,7 +229,7 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer, return -EIO; } -static int bad_inode_permission(struct inode *inode, int mask) +static int bad_inode_permission(struct inode *inode, int mask, unsigned int flags) { return -EIO; } diff --git a/trunk/fs/binfmt_elf.c b/trunk/fs/binfmt_elf.c index dd0fdfc56d38..303983fabfd6 100644 --- a/trunk/fs/binfmt_elf.c +++ b/trunk/fs/binfmt_elf.c @@ -668,7 +668,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) * mm->dumpable = 0 regardless of the interpreter's * permissions. */ - would_dump(bprm, interpreter); + if (file_permission(interpreter, MAY_READ) < 0) + bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); diff --git a/trunk/fs/binfmt_elf_fdpic.c b/trunk/fs/binfmt_elf_fdpic.c index 30745f459faf..2bc5dc644b4c 100644 --- a/trunk/fs/binfmt_elf_fdpic.c +++ b/trunk/fs/binfmt_elf_fdpic.c @@ -245,7 +245,8 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, * mm->dumpable = 0 regardless of the interpreter's * permissions. */ - would_dump(bprm, interpreter); + if (file_permission(interpreter, MAY_READ) < 0) + bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); diff --git a/trunk/fs/binfmt_misc.c b/trunk/fs/binfmt_misc.c index ba1a1ae4a18a..1befe2ec8186 100644 --- a/trunk/fs/binfmt_misc.c +++ b/trunk/fs/binfmt_misc.c @@ -149,7 +149,8 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) /* if the binary is not readable than enforce mm->dumpable=0 regardless of the interpreter's permissions */ - would_dump(bprm, bprm->file); + if (file_permission(bprm->file, MAY_READ)) + bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; allow_write_access(bprm->file); bprm->file = NULL; diff --git a/trunk/fs/block_dev.c b/trunk/fs/block_dev.c index 9fb0b15331d3..610e8e0b04b8 100644 --- a/trunk/fs/block_dev.c +++ b/trunk/fs/block_dev.c @@ -355,30 +355,25 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin) mutex_lock(&bd_inode->i_mutex); size = i_size_read(bd_inode); - retval = -EINVAL; switch (origin) { - case SEEK_END: + case 2: offset += size; break; - case SEEK_CUR: + case 1: offset += file->f_pos; - case SEEK_SET: - break; - default: - goto out; } + retval = -EINVAL; if (offset >= 0 && offset <= size) { if (offset != file->f_pos) { file->f_pos = offset; } retval = offset; } -out: mutex_unlock(&bd_inode->i_mutex); return retval; } -int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync) +int blkdev_fsync(struct file *filp, int datasync) { struct inode *bd_inode = filp->f_mapping->host; struct block_device *bdev = I_BDEV(bd_inode); @@ -389,10 +384,14 @@ int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync) * i_mutex and doing so causes performance issues with concurrent * O_SYNC writers to a block device. */ + mutex_unlock(&bd_inode->i_mutex); + error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL); if (error == -EOPNOTSUPP) error = 0; + mutex_lock(&bd_inode->i_mutex); + return error; } EXPORT_SYMBOL(blkdev_fsync); diff --git a/trunk/fs/btrfs/acl.c b/trunk/fs/btrfs/acl.c index 9f62ab2a7282..f66fc9959733 100644 --- a/trunk/fs/btrfs/acl.c +++ b/trunk/fs/btrfs/acl.c @@ -195,13 +195,14 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, return ret; } -int btrfs_check_acl(struct inode *inode, int mask) +int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags) { int error = -EAGAIN; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) error = -ECHILD; + } else { struct posix_acl *acl; acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); diff --git a/trunk/fs/btrfs/ctree.h b/trunk/fs/btrfs/ctree.h index 82be74efbb26..3b859a3e6a0e 100644 --- a/trunk/fs/btrfs/ctree.h +++ b/trunk/fs/btrfs/ctree.h @@ -1219,7 +1219,7 @@ struct btrfs_root { * right now this just gets used so that a root has its own devid * for stat. It may be used for more later */ - dev_t anon_dev; + struct super_block anon_super; }; struct btrfs_ioctl_defrag_range_args { @@ -2510,9 +2510,6 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans, int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, struct list_head *list, int search_commit); /* inode.c */ -struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page, - size_t pg_offset, u64 start, u64 len, - int create); /* RHEL and EL kernels have a patch that renames PG_checked to FsMisc */ #if defined(ClearPageFsMisc) && !defined(ClearPageChecked) @@ -2605,7 +2602,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, struct inode *inode); int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info); -int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync); +int btrfs_sync_file(struct file *file, int datasync); int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, int skip_pinned); extern const struct file_operations btrfs_file_operations; @@ -2645,7 +2642,7 @@ do { \ /* acl.c */ #ifdef CONFIG_BTRFS_FS_POSIX_ACL -int btrfs_check_acl(struct inode *inode, int mask); +int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags); #else #define btrfs_check_acl NULL #endif diff --git a/trunk/fs/btrfs/disk-io.c b/trunk/fs/btrfs/disk-io.c index b231ae13b269..1ac8db5dc0a3 100644 --- a/trunk/fs/btrfs/disk-io.c +++ b/trunk/fs/btrfs/disk-io.c @@ -1077,7 +1077,12 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, init_completion(&root->kobj_unregister); root->defrag_running = 0; root->root_key.objectid = objectid; - root->anon_dev = 0; + root->anon_super.s_root = NULL; + root->anon_super.s_dev = 0; + INIT_LIST_HEAD(&root->anon_super.s_list); + INIT_LIST_HEAD(&root->anon_super.s_instances); + init_rwsem(&root->anon_super.s_umount); + return 0; } @@ -1306,7 +1311,7 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, spin_lock_init(&root->cache_lock); init_waitqueue_head(&root->cache_wait); - ret = get_anon_bdev(&root->anon_dev); + ret = set_anon_super(&root->anon_super, NULL); if (ret) goto fail; @@ -2388,8 +2393,10 @@ static void free_fs_root(struct btrfs_root *root) { iput(root->cache_inode); WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); - if (root->anon_dev) - free_anon_bdev(root->anon_dev); + if (root->anon_super.s_dev) { + down_write(&root->anon_super.s_umount); + kill_anon_super(&root->anon_super); + } free_extent_buffer(root->node); free_extent_buffer(root->commit_root); kfree(root->free_ino_ctl); diff --git a/trunk/fs/btrfs/file.c b/trunk/fs/btrfs/file.c index 59cbdb120ad0..fa4ef18b66b1 100644 --- a/trunk/fs/btrfs/file.c +++ b/trunk/fs/btrfs/file.c @@ -1452,7 +1452,7 @@ int btrfs_release_file(struct inode *inode, struct file *filp) * important optimization for directories because holding the mutex prevents * new operations on the dir while we write to disk. */ -int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +int btrfs_sync_file(struct file *file, int datasync) { struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; @@ -1462,13 +1462,9 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) trace_btrfs_sync_file(file, datasync); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - /* we wait first, since the writeback may change the inode */ root->log_batch++; + /* the VFS called filemap_fdatawrite for us */ btrfs_wait_ordered_range(inode, 0, (u64)-1); root->log_batch++; @@ -1476,10 +1472,8 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) * check the transaction that last modified this inode * and see if its already been committed */ - if (!BTRFS_I(inode)->last_trans) { - mutex_unlock(&inode->i_mutex); + if (!BTRFS_I(inode)->last_trans) goto out; - } /* * if the last transaction that changed this file was before @@ -1490,7 +1484,6 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) if (BTRFS_I(inode)->last_trans <= root->fs_info->last_trans_committed) { BTRFS_I(inode)->last_trans = 0; - mutex_unlock(&inode->i_mutex); goto out; } @@ -1503,15 +1496,12 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { ret = PTR_ERR(trans); - mutex_unlock(&inode->i_mutex); goto out; } ret = btrfs_log_dentry_safe(trans, root, dentry); - if (ret < 0) { - mutex_unlock(&inode->i_mutex); + if (ret < 0) goto out; - } /* we've logged all the items and now have a consistent * version of the file in the log. It is possible that @@ -1523,7 +1513,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) * file again, but that will end up using the synchronization * inside btrfs_sync_log to keep things safe. */ - mutex_unlock(&inode->i_mutex); + mutex_unlock(&dentry->d_inode->i_mutex); if (ret != BTRFS_NO_LOG_SYNC) { if (ret > 0) { @@ -1538,6 +1528,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) } else { ret = btrfs_end_transaction(trans, root); } + mutex_lock(&dentry->d_inode->i_mutex); out: return ret > 0 ? -EIO : ret; } @@ -1673,154 +1664,8 @@ static long btrfs_fallocate(struct file *file, int mode, return ret; } -static int find_desired_extent(struct inode *inode, loff_t *offset, int origin) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_map *em; - struct extent_state *cached_state = NULL; - u64 lockstart = *offset; - u64 lockend = i_size_read(inode); - u64 start = *offset; - u64 orig_start = *offset; - u64 len = i_size_read(inode); - u64 last_end = 0; - int ret = 0; - - lockend = max_t(u64, root->sectorsize, lockend); - if (lockend <= lockstart) - lockend = lockstart + root->sectorsize; - - len = lockend - lockstart + 1; - - len = max_t(u64, len, root->sectorsize); - if (inode->i_size == 0) - return -ENXIO; - - lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0, - &cached_state, GFP_NOFS); - - /* - * Delalloc is such a pain. If we have a hole and we have pending - * delalloc for a portion of the hole we will get back a hole that - * exists for the entire range since it hasn't been actually written - * yet. So to take care of this case we need to look for an extent just - * before the position we want in case there is outstanding delalloc - * going on here. - */ - if (origin == SEEK_HOLE && start != 0) { - if (start <= root->sectorsize) - em = btrfs_get_extent_fiemap(inode, NULL, 0, 0, - root->sectorsize, 0); - else - em = btrfs_get_extent_fiemap(inode, NULL, 0, - start - root->sectorsize, - root->sectorsize, 0); - if (IS_ERR(em)) { - ret = -ENXIO; - goto out; - } - last_end = em->start + em->len; - if (em->block_start == EXTENT_MAP_DELALLOC) - last_end = min_t(u64, last_end, inode->i_size); - free_extent_map(em); - } - - while (1) { - em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0); - if (IS_ERR(em)) { - ret = -ENXIO; - break; - } - - if (em->block_start == EXTENT_MAP_HOLE) { - if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) { - if (last_end <= orig_start) { - free_extent_map(em); - ret = -ENXIO; - break; - } - } - - if (origin == SEEK_HOLE) { - *offset = start; - free_extent_map(em); - break; - } - } else { - if (origin == SEEK_DATA) { - if (em->block_start == EXTENT_MAP_DELALLOC) { - if (start >= inode->i_size) { - free_extent_map(em); - ret = -ENXIO; - break; - } - } - - *offset = start; - free_extent_map(em); - break; - } - } - - start = em->start + em->len; - last_end = em->start + em->len; - - if (em->block_start == EXTENT_MAP_DELALLOC) - last_end = min_t(u64, last_end, inode->i_size); - - if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) { - free_extent_map(em); - ret = -ENXIO; - break; - } - free_extent_map(em); - cond_resched(); - } - if (!ret) - *offset = min(*offset, inode->i_size); -out: - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, - &cached_state, GFP_NOFS); - return ret; -} - -static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin) -{ - struct inode *inode = file->f_mapping->host; - int ret; - - mutex_lock(&inode->i_mutex); - switch (origin) { - case SEEK_END: - case SEEK_CUR: - offset = generic_file_llseek_unlocked(file, offset, origin); - goto out; - case SEEK_DATA: - case SEEK_HOLE: - ret = find_desired_extent(inode, &offset, origin); - if (ret) { - mutex_unlock(&inode->i_mutex); - return ret; - } - } - - if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) - return -EINVAL; - if (offset > inode->i_sb->s_maxbytes) - return -EINVAL; - - /* Special lock needed here? */ - if (offset != file->f_pos) { - file->f_pos = offset; - file->f_version = 0; - } -out: - mutex_unlock(&inode->i_mutex); - return offset; -} - const struct file_operations btrfs_file_operations = { - .llseek = btrfs_file_llseek, + .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, diff --git a/trunk/fs/btrfs/inode.c b/trunk/fs/btrfs/inode.c index 2548a04a0230..3601f0aebddf 100644 --- a/trunk/fs/btrfs/inode.c +++ b/trunk/fs/btrfs/inode.c @@ -4079,7 +4079,13 @@ static int btrfs_dentry_delete(const struct dentry *dentry) static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - return d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry); + struct inode *inode; + + inode = btrfs_lookup_dentry(dir, dentry); + if (IS_ERR(inode)) + return ERR_CAST(inode); + + return d_splice_alias(inode, dentry); } unsigned char btrfs_filetype_table[] = { @@ -4766,10 +4772,11 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, if (err) { drop_inode = 1; } else { - struct dentry *parent = dentry->d_parent; + struct dentry *parent = dget_parent(dentry); err = btrfs_update_inode(trans, root, inode); BUG_ON(err); btrfs_log_new_name(trans, inode, NULL, parent); + dput(parent); } nr = trans->blocks_used; @@ -6893,7 +6900,7 @@ static int btrfs_getattr(struct vfsmount *mnt, { struct inode *inode = dentry->d_inode; generic_fillattr(inode, stat); - stat->dev = BTRFS_I(inode)->root->anon_dev; + stat->dev = BTRFS_I(inode)->root->anon_super.s_dev; stat->blksize = PAGE_CACHE_SIZE; stat->blocks = (inode_get_bytes(inode) + BTRFS_I(inode)->delalloc_bytes) >> 9; @@ -7061,8 +7068,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, BUG_ON(ret); if (old_ino != BTRFS_FIRST_FREE_OBJECTID) { - struct dentry *parent = new_dentry->d_parent; + struct dentry *parent = dget_parent(new_dentry); btrfs_log_new_name(trans, old_inode, old_dir, parent); + dput(parent); btrfs_end_log_trans(root); } out_fail: @@ -7323,7 +7331,7 @@ static int btrfs_set_page_dirty(struct page *page) return __set_page_dirty_nobuffers(page); } -static int btrfs_permission(struct inode *inode, int mask) +static int btrfs_permission(struct inode *inode, int mask, unsigned int flags) { struct btrfs_root *root = BTRFS_I(inode)->root; @@ -7331,7 +7339,7 @@ static int btrfs_permission(struct inode *inode, int mask) return -EROFS; if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) return -EACCES; - return generic_permission(inode, mask); + return generic_permission(inode, mask, flags, btrfs_check_acl); } static const struct inode_operations btrfs_dir_inode_operations = { @@ -7351,12 +7359,10 @@ static const struct inode_operations btrfs_dir_inode_operations = { .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, .permission = btrfs_permission, - .check_acl = btrfs_check_acl, }; static const struct inode_operations btrfs_dir_ro_inode_operations = { .lookup = btrfs_lookup, .permission = btrfs_permission, - .check_acl = btrfs_check_acl, }; static const struct file_operations btrfs_dir_file_operations = { @@ -7425,7 +7431,6 @@ static const struct inode_operations btrfs_file_inode_operations = { .removexattr = btrfs_removexattr, .permission = btrfs_permission, .fiemap = btrfs_fiemap, - .check_acl = btrfs_check_acl, }; static const struct inode_operations btrfs_special_inode_operations = { .getattr = btrfs_getattr, @@ -7435,7 +7440,6 @@ static const struct inode_operations btrfs_special_inode_operations = { .getxattr = btrfs_getxattr, .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, - .check_acl = btrfs_check_acl, }; static const struct inode_operations btrfs_symlink_inode_operations = { .readlink = generic_readlink, @@ -7447,7 +7451,6 @@ static const struct inode_operations btrfs_symlink_inode_operations = { .getxattr = btrfs_getxattr, .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, - .check_acl = btrfs_check_acl, }; const struct dentry_operations btrfs_dentry_operations = { diff --git a/trunk/fs/btrfs/ioctl.c b/trunk/fs/btrfs/ioctl.c index 622543309eb2..a3c4751e07db 100644 --- a/trunk/fs/btrfs/ioctl.c +++ b/trunk/fs/btrfs/ioctl.c @@ -323,7 +323,7 @@ static noinline int create_subvol(struct btrfs_root *root, struct btrfs_inode_item *inode_item; struct extent_buffer *leaf; struct btrfs_root *new_root; - struct dentry *parent = dentry->d_parent; + struct dentry *parent = dget_parent(dentry); struct inode *dir; int ret; int err; @@ -332,8 +332,10 @@ static noinline int create_subvol(struct btrfs_root *root, u64 index = 0; ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); - if (ret) + if (ret) { + dput(parent); return ret; + } dir = parent->d_inode; @@ -344,8 +346,10 @@ static noinline int create_subvol(struct btrfs_root *root, * 2 - dir items */ trans = btrfs_start_transaction(root, 6); - if (IS_ERR(trans)) + if (IS_ERR(trans)) { + dput(parent); return PTR_ERR(trans); + } leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0, objectid, NULL, 0, 0, 0); @@ -435,6 +439,7 @@ static noinline int create_subvol(struct btrfs_root *root, d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); fail: + dput(parent); if (async_transid) { *async_transid = trans->transid; err = btrfs_commit_transaction_async(trans, root, 1); @@ -451,6 +456,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, bool readonly) { struct inode *inode; + struct dentry *parent; struct btrfs_pending_snapshot *pending_snapshot; struct btrfs_trans_handle *trans; int ret; @@ -498,7 +504,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, if (ret) goto fail; - inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); + parent = dget_parent(dentry); + inode = btrfs_lookup_dentry(parent->d_inode, dentry); + dput(parent); if (IS_ERR(inode)) { ret = PTR_ERR(inode); goto fail; diff --git a/trunk/fs/cachefiles/bind.c b/trunk/fs/cachefiles/bind.c index 622f4696e484..a2603e7c0bb5 100644 --- a/trunk/fs/cachefiles/bind.c +++ b/trunk/fs/cachefiles/bind.c @@ -129,6 +129,8 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) !root->d_inode->i_op->mkdir || !root->d_inode->i_op->setxattr || !root->d_inode->i_op->getxattr || + !root->d_sb || + !root->d_sb->s_op || !root->d_sb->s_op->statfs || !root->d_sb->s_op->sync_fs) goto error_unsupported; diff --git a/trunk/fs/ceph/caps.c b/trunk/fs/ceph/caps.c index 8d74ad7ba556..f605753c8fe9 100644 --- a/trunk/fs/ceph/caps.c +++ b/trunk/fs/ceph/caps.c @@ -1811,7 +1811,7 @@ static void sync_write_wait(struct inode *inode) spin_unlock(&ci->i_unsafe_lock); } -int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int ceph_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; struct ceph_inode_info *ci = ceph_inode(inode); @@ -1822,10 +1822,9 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) dout("fsync %p%s\n", inode, datasync ? " datasync" : ""); sync_write_wait(inode); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); + ret = filemap_write_and_wait(inode->i_mapping); if (ret < 0) return ret; - mutex_lock(&inode->i_mutex); dirty = try_flush_caps(inode, NULL, &flush_tid); dout("fsync dirty caps are %s\n", ceph_cap_string(dirty)); @@ -1842,7 +1841,6 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) } dout("fsync %p%s done\n", inode, datasync ? " datasync" : ""); - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/ceph/dir.c b/trunk/fs/ceph/dir.c index 1065ac779840..ef8f08c343e8 100644 --- a/trunk/fs/ceph/dir.c +++ b/trunk/fs/ceph/dir.c @@ -252,7 +252,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) off = 1; } if (filp->f_pos == 1) { - ino_t ino = parent_ino(filp->f_dentry); + ino_t ino = filp->f_dentry->d_parent->d_inode->i_ino; dout("readdir off 1 -> '..'\n"); if (filldir(dirent, "..", 2, ceph_make_fpos(0, 1), ceph_translate_ino(inode->i_sb, ino), @@ -446,19 +446,14 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin) loff_t retval; mutex_lock(&inode->i_mutex); - retval = -EINVAL; switch (origin) { case SEEK_END: offset += inode->i_size + 2; /* FIXME */ break; case SEEK_CUR: offset += file->f_pos; - case SEEK_SET: - break; - default: - goto out; } - + retval = -EINVAL; if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { if (offset != file->f_pos) { file->f_pos = offset; @@ -482,7 +477,6 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin) if (offset > old_offset) fi->dir_release_count--; } -out: mutex_unlock(&inode->i_mutex); return retval; } @@ -572,6 +566,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, /* open (but not create!) intent? */ if (nd && (nd->flags & LOOKUP_OPEN) && + (nd->flags & LOOKUP_CONTINUE) == 0 && /* only open last component */ !(nd->intent.open.flags & O_CREAT)) { int mode = nd->intent.open.create_mode & ~current->fs->umask; return ceph_lookup_open(dir, dentry, nd, mode, 1); @@ -1118,8 +1113,7 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size, * an fsync() on a dir will wait for any uncommitted directory * operations to commit. */ -static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int ceph_dir_fsync(struct file *file, int datasync) { struct inode *inode = file->f_path.dentry->d_inode; struct ceph_inode_info *ci = ceph_inode(inode); @@ -1129,11 +1123,6 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, int ret = 0; dout("dir_fsync %p\n", inode); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - spin_lock(&ci->i_unsafe_lock); if (list_empty(head)) goto out; @@ -1167,8 +1156,6 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, } while (req->r_tid < last_tid); out: spin_unlock(&ci->i_unsafe_lock); - mutex_unlock(&inode->i_mutex); - return ret; } diff --git a/trunk/fs/ceph/file.c b/trunk/fs/ceph/file.c index 0d0eae05598f..4698a5c553dc 100644 --- a/trunk/fs/ceph/file.c +++ b/trunk/fs/ceph/file.c @@ -226,7 +226,7 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, struct inode *parent_inode = get_dentry_parent_inode(file->f_dentry); struct ceph_mds_request *req; int err; - int flags = nd->intent.open.flags; + int flags = nd->intent.open.flags - 1; /* silly vfs! */ dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n", dentry, dentry->d_name.len, dentry->d_name.name, flags, mode); @@ -768,16 +768,13 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin) mutex_lock(&inode->i_mutex); __ceph_do_pending_vmtruncate(inode); - if (origin != SEEK_CUR || origin != SEEK_SET) { + switch (origin) { + case SEEK_END: ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE); if (ret < 0) { offset = ret; goto out; } - } - - switch (origin) { - case SEEK_END: offset += inode->i_size; break; case SEEK_CUR: @@ -793,19 +790,6 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin) } offset += file->f_pos; break; - case SEEK_DATA: - if (offset >= inode->i_size) { - ret = -ENXIO; - goto out; - } - break; - case SEEK_HOLE: - if (offset >= inode->i_size) { - ret = -ENXIO; - goto out; - } - offset = inode->i_size; - break; } if (offset < 0 || offset > inode->i_sb->s_maxbytes) { diff --git a/trunk/fs/ceph/inode.c b/trunk/fs/ceph/inode.c index dfb2831d8d85..d8858e96ab18 100644 --- a/trunk/fs/ceph/inode.c +++ b/trunk/fs/ceph/inode.c @@ -1795,17 +1795,17 @@ int ceph_do_getattr(struct inode *inode, int mask) * Check inode permissions. We verify we have a valid value for * the AUTH cap, then call the generic handler. */ -int ceph_permission(struct inode *inode, int mask) +int ceph_permission(struct inode *inode, int mask, unsigned int flags) { int err; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED); if (!err) - err = generic_permission(inode, mask); + err = generic_permission(inode, mask, flags, NULL); return err; } diff --git a/trunk/fs/ceph/super.h b/trunk/fs/ceph/super.h index 30446b144e3d..f5cabefa98dc 100644 --- a/trunk/fs/ceph/super.h +++ b/trunk/fs/ceph/super.h @@ -692,7 +692,7 @@ extern void ceph_queue_invalidate(struct inode *inode); extern void ceph_queue_writeback(struct inode *inode); extern int ceph_do_getattr(struct inode *inode, int mask); -extern int ceph_permission(struct inode *inode, int mask); +extern int ceph_permission(struct inode *inode, int mask, unsigned int flags); extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); @@ -728,8 +728,7 @@ extern void ceph_put_cap(struct ceph_mds_client *mdsc, extern void ceph_queue_caps_release(struct inode *inode); extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc); -extern int ceph_fsync(struct file *file, loff_t start, loff_t end, - int datasync); +extern int ceph_fsync(struct file *file, int datasync); extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc, struct ceph_mds_session *session); extern struct ceph_cap *ceph_get_cap_for_mds(struct ceph_inode_info *ci, diff --git a/trunk/fs/cifs/cifsfs.c b/trunk/fs/cifs/cifsfs.c index 865517470967..bc4b12ca537b 100644 --- a/trunk/fs/cifs/cifsfs.c +++ b/trunk/fs/cifs/cifsfs.c @@ -224,7 +224,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static int cifs_permission(struct inode *inode, int mask) +static int cifs_permission(struct inode *inode, int mask, unsigned int flags) { struct cifs_sb_info *cifs_sb; @@ -239,7 +239,7 @@ static int cifs_permission(struct inode *inode, int mask) on the client (above and beyond ACL on servers) for servers which do not support setting and viewing mode bits, so allowing client to check permissions is useful */ - return generic_permission(inode, mask); + return generic_permission(inode, mask, flags, NULL); } static struct kmem_cache *cifs_inode_cachep; @@ -704,11 +704,8 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) { - /* - * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate - * the cached file length - */ - if (origin != SEEK_SET || origin != SEEK_CUR) { + /* origin == SEEK_END => we must revalidate the cached file length */ + if (origin == SEEK_END) { int rc; struct inode *inode = file->f_path.dentry->d_inode; diff --git a/trunk/fs/cifs/cifsfs.h b/trunk/fs/cifs/cifsfs.h index fbd050c8d52a..036ca83e5f46 100644 --- a/trunk/fs/cifs/cifsfs.h +++ b/trunk/fs/cifs/cifsfs.h @@ -91,8 +91,8 @@ extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); extern int cifs_lock(struct file *, int, struct file_lock *); -extern int cifs_fsync(struct file *, loff_t, loff_t, int); -extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int); +extern int cifs_fsync(struct file *, int); +extern int cifs_strict_fsync(struct file *, int); extern int cifs_flush(struct file *, fl_owner_t id); extern int cifs_file_mmap(struct file * , struct vm_area_struct *); extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *); diff --git a/trunk/fs/cifs/connect.c b/trunk/fs/cifs/connect.c index e66297bad412..ccc1afa0bf3b 100644 --- a/trunk/fs/cifs/connect.c +++ b/trunk/fs/cifs/connect.c @@ -320,10 +320,9 @@ cifs_echo_request(struct work_struct *work) } static int -cifs_demultiplex_thread(void *p) +cifs_demultiplex_thread(struct TCP_Server_Info *server) { int length; - struct TCP_Server_Info *server = p; unsigned int pdu_length, total_read; struct smb_hdr *smb_buffer = NULL; struct smb_hdr *bigbuf = NULL; @@ -1792,7 +1791,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) * this will succeed. No need for try_module_get(). */ __module_get(THIS_MODULE); - tcp_ses->tsk = kthread_run(cifs_demultiplex_thread, + tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, tcp_ses, "cifsd"); if (IS_ERR(tcp_ses->tsk)) { rc = PTR_ERR(tcp_ses->tsk); diff --git a/trunk/fs/cifs/dir.c b/trunk/fs/cifs/dir.c index 14d602f178c2..fa8c21d913bc 100644 --- a/trunk/fs/cifs/dir.c +++ b/trunk/fs/cifs/dir.c @@ -179,7 +179,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, if (oplockEnabled) oplock = REQ_OPLOCK; - if (nd) + if (nd && (nd->flags & LOOKUP_OPEN)) oflags = nd->intent.open.file->f_flags; else oflags = O_RDONLY | O_CREAT; @@ -214,7 +214,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, which should be rare for path not covered on files) */ } - if (nd) { + if (nd && (nd->flags & LOOKUP_OPEN)) { /* if the file is going to stay open, then we need to set the desired access properly */ desiredAccess = 0; @@ -328,7 +328,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, else cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); - if (newinode && nd) { + if (newinode && nd && (nd->flags & LOOKUP_OPEN)) { struct cifsFileInfo *pfile_info; struct file *filp; @@ -568,7 +568,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, * reduction in network traffic in the other paths. */ if (pTcon->unix_ext) { - if (nd && !(nd->flags & LOOKUP_DIRECTORY) && + if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && (nd->intent.open.file->f_flags & O_CREAT)) { rc = cifs_posix_open(full_path, &newInode, @@ -663,8 +663,10 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) * case sensitive name which is specified by user if this is * for creation. */ - if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) - return 0; + if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { + if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + } if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled) return 0; diff --git a/trunk/fs/cifs/file.c b/trunk/fs/cifs/file.c index 378acdafa356..a9b4a24f2a16 100644 --- a/trunk/fs/cifs/file.c +++ b/trunk/fs/cifs/file.c @@ -1401,8 +1401,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, return rc; } -int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +int cifs_strict_fsync(struct file *file, int datasync) { int xid; int rc = 0; @@ -1411,11 +1410,6 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, struct inode *inode = file->f_path.dentry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - rc = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (rc) - return rc; - mutex_lock(&inode->i_mutex); - xid = GetXid(); cFYI(1, "Sync file - name: %s datasync: 0x%x", @@ -1434,23 +1428,16 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); FreeXid(xid); - mutex_unlock(&inode->i_mutex); return rc; } -int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int cifs_fsync(struct file *file, int datasync) { int xid; int rc = 0; struct cifs_tcon *tcon; struct cifsFileInfo *smbfile = file->private_data; struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - struct inode *inode = file->f_mapping->host; - - rc = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (rc) - return rc; - mutex_lock(&inode->i_mutex); xid = GetXid(); @@ -1462,7 +1449,6 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); FreeXid(xid); - mutex_unlock(&inode->i_mutex); return rc; } diff --git a/trunk/fs/cifs/readdir.c b/trunk/fs/cifs/readdir.c index 965a3af186a1..6751e745bbc6 100644 --- a/trunk/fs/cifs/readdir.c +++ b/trunk/fs/cifs/readdir.c @@ -796,7 +796,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) file->f_pos++; case 1: if (filldir(direntry, "..", 2, file->f_pos, - parent_ino(file->f_path.dentry), DT_DIR) < 0) { + file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { cERROR(1, "Filldir for parent dir failed"); rc = -ENOMEM; break; diff --git a/trunk/fs/coda/coda_int.h b/trunk/fs/coda/coda_int.h index b7143cf783ac..6b443ff43a19 100644 --- a/trunk/fs/coda/coda_int.h +++ b/trunk/fs/coda/coda_int.h @@ -11,7 +11,7 @@ extern int coda_fake_statfs; void coda_destroy_inodecache(void); int coda_init_inodecache(void); -int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync); +int coda_fsync(struct file *coda_file, int datasync); void coda_sysctl_init(void); void coda_sysctl_clean(void); diff --git a/trunk/fs/coda/coda_linux.h b/trunk/fs/coda/coda_linux.h index 44e17e9c21ae..9b0c5323890b 100644 --- a/trunk/fs/coda/coda_linux.h +++ b/trunk/fs/coda/coda_linux.h @@ -39,7 +39,7 @@ extern const struct file_operations coda_ioctl_operations; /* operations shared over more than one file */ int coda_open(struct inode *i, struct file *f); int coda_release(struct inode *i, struct file *f); -int coda_permission(struct inode *inode, int mask); +int coda_permission(struct inode *inode, int mask, unsigned int flags); int coda_revalidate_inode(struct dentry *); int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *); int coda_setattr(struct dentry *, struct iattr *); diff --git a/trunk/fs/coda/dir.c b/trunk/fs/coda/dir.c index 0239433f50cb..2b8dae4d121e 100644 --- a/trunk/fs/coda/dir.c +++ b/trunk/fs/coda/dir.c @@ -132,11 +132,11 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc } -int coda_permission(struct inode *inode, int mask) +int coda_permission(struct inode *inode, int mask, unsigned int flags) { int error; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; mask &= MAY_READ | MAY_WRITE | MAY_EXEC; @@ -449,7 +449,8 @@ static int coda_venus_readdir(struct file *coda_file, void *buf, struct file *host_file; struct dentry *de; struct venus_dirent *vdir; - unsigned long vdir_size = offsetof(struct venus_dirent, d_name); + unsigned long vdir_size = + (unsigned long)(&((struct venus_dirent *)0)->d_name); unsigned int type; struct qstr name; ino_t ino; @@ -473,7 +474,7 @@ static int coda_venus_readdir(struct file *coda_file, void *buf, coda_file->f_pos++; } if (coda_file->f_pos == 1) { - ret = filldir(buf, "..", 2, 1, parent_ino(de), DT_DIR); + ret = filldir(buf, "..", 2, 1, de->d_parent->d_inode->i_ino, DT_DIR); if (ret < 0) goto out; result++; diff --git a/trunk/fs/coda/file.c b/trunk/fs/coda/file.c index 8edd404e6419..0433057be330 100644 --- a/trunk/fs/coda/file.c +++ b/trunk/fs/coda/file.c @@ -199,7 +199,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file) return 0; } -int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) +int coda_fsync(struct file *coda_file, int datasync) { struct file *host_file; struct inode *coda_inode = coda_file->f_path.dentry->d_inode; @@ -210,11 +210,6 @@ int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) S_ISLNK(coda_inode->i_mode))) return -EINVAL; - err = filemap_write_and_wait_range(coda_inode->i_mapping, start, end); - if (err) - return err; - mutex_lock(&coda_inode->i_mutex); - cfi = CODA_FTOC(coda_file); BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); host_file = cfi->cfi_container; @@ -222,7 +217,6 @@ int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) err = vfs_fsync(host_file, datasync); if (!err && !datasync) err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode)); - mutex_unlock(&coda_inode->i_mutex); return err; } diff --git a/trunk/fs/coda/pioctl.c b/trunk/fs/coda/pioctl.c index ee0981f1375b..cb140ef293e4 100644 --- a/trunk/fs/coda/pioctl.c +++ b/trunk/fs/coda/pioctl.c @@ -24,7 +24,7 @@ #include "coda_linux.h" /* pioctl ops */ -static int coda_ioctl_permission(struct inode *inode, int mask); +static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags); static long coda_pioctl(struct file *filp, unsigned int cmd, unsigned long user_data); @@ -41,7 +41,7 @@ const struct file_operations coda_ioctl_operations = { }; /* the coda pioctl inode ops */ -static int coda_ioctl_permission(struct inode *inode, int mask) +static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags) { return (mask & MAY_EXEC) ? -EACCES : 0; } diff --git a/trunk/fs/dcache.c b/trunk/fs/dcache.c index be18598c7fd7..fbdcbca40725 100644 --- a/trunk/fs/dcache.c +++ b/trunk/fs/dcache.c @@ -343,24 +343,6 @@ void d_drop(struct dentry *dentry) } EXPORT_SYMBOL(d_drop); -/* - * d_clear_need_lookup - drop a dentry from cache and clear the need lookup flag - * @dentry: dentry to drop - * - * This is called when we do a lookup on a placeholder dentry that needed to be - * looked up. The dentry should have been hashed in order for it to be found by - * the lookup code, but now needs to be unhashed while we do the actual lookup - * and clear the DCACHE_NEED_LOOKUP flag. - */ -void d_clear_need_lookup(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - __d_drop(dentry); - dentry->d_flags &= ~DCACHE_NEED_LOOKUP; - spin_unlock(&dentry->d_lock); -} -EXPORT_SYMBOL(d_clear_need_lookup); - /* * Finish off a dentry we've decided to kill. * dentry->d_lock must be held, returns with it unlocked. @@ -450,13 +432,8 @@ void dput(struct dentry *dentry) if (d_unhashed(dentry)) goto kill_it; - /* - * If this dentry needs lookup, don't set the referenced flag so that it - * is more likely to be cleaned up by the dcache shrinker in case of - * memory pressure. - */ - if (!d_need_lookup(dentry)) - dentry->d_flags |= DCACHE_REFERENCED; + /* Otherwise leave it cached and ensure it's on the LRU */ + dentry->d_flags |= DCACHE_REFERENCED; dentry_lru_add(dentry); dentry->d_count--; @@ -549,6 +526,10 @@ struct dentry *dget_parent(struct dentry *dentry) */ rcu_read_lock(); ret = dentry->d_parent; + if (!ret) { + rcu_read_unlock(); + goto out; + } spin_lock(&ret->d_lock); if (unlikely(ret != dentry->d_parent)) { spin_unlock(&ret->d_lock); @@ -559,6 +540,7 @@ struct dentry *dget_parent(struct dentry *dentry) BUG_ON(!ret->d_count); ret->d_count++; spin_unlock(&ret->d_lock); +out: return ret; } EXPORT_SYMBOL(dget_parent); @@ -738,11 +720,13 @@ static void shrink_dentry_list(struct list_head *list) * * If flags contains DCACHE_REFERENCED reference dentries will not be pruned. */ -static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) +static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags) { + /* called from prune_dcache() and shrink_dcache_parent() */ struct dentry *dentry; LIST_HEAD(referenced); LIST_HEAD(tmp); + int cnt = *count; relock: spin_lock(&dcache_lru_lock); @@ -770,7 +754,7 @@ static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) } else { list_move_tail(&dentry->d_lru, &tmp); spin_unlock(&dentry->d_lock); - if (!--count) + if (!--cnt) break; } cond_resched_lock(&dcache_lru_lock); @@ -780,22 +764,83 @@ static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) spin_unlock(&dcache_lru_lock); shrink_dentry_list(&tmp); + + *count = cnt; } /** - * prune_dcache_sb - shrink the dcache - * @nr_to_scan: number of entries to try to free + * prune_dcache - shrink the dcache + * @count: number of entries to try to free * - * Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is - * done when we need more memory an called from the superblock shrinker - * function. + * Shrink the dcache. This is done when we need more memory, or simply when we + * need to unmount something (at which point we need to unuse all dentries). * - * This function may fail to free any resources if all the dentries are in - * use. + * This function may fail to free any resources if all the dentries are in use. */ -void prune_dcache_sb(struct super_block *sb, int nr_to_scan) +static void prune_dcache(int count) { - __shrink_dcache_sb(sb, nr_to_scan, DCACHE_REFERENCED); + struct super_block *sb, *p = NULL; + int w_count; + int unused = dentry_stat.nr_unused; + int prune_ratio; + int pruned; + + if (unused == 0 || count == 0) + return; + if (count >= unused) + prune_ratio = 1; + else + prune_ratio = unused / count; + spin_lock(&sb_lock); + list_for_each_entry(sb, &super_blocks, s_list) { + if (list_empty(&sb->s_instances)) + continue; + if (sb->s_nr_dentry_unused == 0) + continue; + sb->s_count++; + /* Now, we reclaim unused dentrins with fairness. + * We reclaim them same percentage from each superblock. + * We calculate number of dentries to scan on this sb + * as follows, but the implementation is arranged to avoid + * overflows: + * number of dentries to scan on this sb = + * count * (number of dentries on this sb / + * number of dentries in the machine) + */ + spin_unlock(&sb_lock); + if (prune_ratio != 1) + w_count = (sb->s_nr_dentry_unused / prune_ratio) + 1; + else + w_count = sb->s_nr_dentry_unused; + pruned = w_count; + /* + * We need to be sure this filesystem isn't being unmounted, + * otherwise we could race with generic_shutdown_super(), and + * end up holding a reference to an inode while the filesystem + * is unmounted. So we try to get s_umount, and make sure + * s_root isn't NULL. + */ + if (down_read_trylock(&sb->s_umount)) { + if ((sb->s_root != NULL) && + (!list_empty(&sb->s_dentry_lru))) { + __shrink_dcache_sb(sb, &w_count, + DCACHE_REFERENCED); + pruned -= w_count; + } + up_read(&sb->s_umount); + } + spin_lock(&sb_lock); + if (p) + __put_super(p); + count -= pruned; + p = sb; + /* more work left to do? */ + if (count <= 0) + break; + } + if (p) + __put_super(p); + spin_unlock(&sb_lock); } /** @@ -1170,13 +1215,45 @@ void shrink_dcache_parent(struct dentry * parent) int found; while ((found = select_parent(parent)) != 0) - __shrink_dcache_sb(sb, found, 0); + __shrink_dcache_sb(sb, &found, 0); } EXPORT_SYMBOL(shrink_dcache_parent); +/* + * Scan `sc->nr_slab_to_reclaim' dentries and return the number which remain. + * + * We need to avoid reentering the filesystem if the caller is performing a + * GFP_NOFS allocation attempt. One example deadlock is: + * + * ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache-> + * prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op->put_inode-> + * ext2_discard_prealloc->ext2_free_blocks->lock_super->DEADLOCK. + * + * In this case we return -1 to tell the caller that we baled. + */ +static int shrink_dcache_memory(struct shrinker *shrink, + struct shrink_control *sc) +{ + int nr = sc->nr_to_scan; + gfp_t gfp_mask = sc->gfp_mask; + + if (nr) { + if (!(gfp_mask & __GFP_FS)) + return -1; + prune_dcache(nr); + } + + return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; +} + +static struct shrinker dcache_shrinker = { + .shrink = shrink_dcache_memory, + .seeks = DEFAULT_SEEKS, +}; + /** - * __d_alloc - allocate a dcache entry - * @sb: filesystem it will belong to + * d_alloc - allocate a dcache entry + * @parent: parent of entry to allocate * @name: qstr of the name * * Allocates a dentry. It returns %NULL if there is insufficient memory @@ -1184,7 +1261,7 @@ EXPORT_SYMBOL(shrink_dcache_parent); * copied and the copy passed in may be reused after this call. */ -struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) +struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) { struct dentry *dentry; char *dname; @@ -1214,8 +1291,8 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) spin_lock_init(&dentry->d_lock); seqcount_init(&dentry->d_seq); dentry->d_inode = NULL; - dentry->d_parent = dentry; - dentry->d_sb = sb; + dentry->d_parent = NULL; + dentry->d_sb = NULL; dentry->d_op = NULL; dentry->d_fsdata = NULL; INIT_HLIST_BL_NODE(&dentry->d_hash); @@ -1223,37 +1300,22 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) INIT_LIST_HEAD(&dentry->d_subdirs); INIT_LIST_HEAD(&dentry->d_alias); INIT_LIST_HEAD(&dentry->d_u.d_child); - d_set_d_op(dentry, dentry->d_sb->s_d_op); - this_cpu_inc(nr_dentry); - - return dentry; -} - -/** - * d_alloc - allocate a dcache entry - * @parent: parent of entry to allocate - * @name: qstr of the name - * - * Allocates a dentry. It returns %NULL if there is insufficient memory - * available. On a success the dentry is returned. The name passed in is - * copied and the copy passed in may be reused after this call. - */ -struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) -{ - struct dentry *dentry = __d_alloc(parent->d_sb, name); - if (!dentry) - return NULL; + if (parent) { + spin_lock(&parent->d_lock); + /* + * don't need child lock because it is not subject + * to concurrency here + */ + __dget_dlock(parent); + dentry->d_parent = parent; + dentry->d_sb = parent->d_sb; + d_set_d_op(dentry, dentry->d_sb->s_d_op); + list_add(&dentry->d_u.d_child, &parent->d_subdirs); + spin_unlock(&parent->d_lock); + } - spin_lock(&parent->d_lock); - /* - * don't need child lock because it is not subject - * to concurrency here - */ - __dget_dlock(parent); - dentry->d_parent = parent; - list_add(&dentry->d_u.d_child, &parent->d_subdirs); - spin_unlock(&parent->d_lock); + this_cpu_inc(nr_dentry); return dentry; } @@ -1261,9 +1323,13 @@ EXPORT_SYMBOL(d_alloc); struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) { - struct dentry *dentry = __d_alloc(sb, name); - if (dentry) + struct dentry *dentry = d_alloc(NULL, name); + if (dentry) { + dentry->d_sb = sb; + d_set_d_op(dentry, dentry->d_sb->s_d_op); + dentry->d_parent = dentry; dentry->d_flags |= DCACHE_DISCONNECTED; + } return dentry; } EXPORT_SYMBOL(d_alloc_pseudo); @@ -1433,9 +1499,13 @@ struct dentry * d_alloc_root(struct inode * root_inode) if (root_inode) { static const struct qstr name = { .name = "/", .len = 1 }; - res = __d_alloc(root_inode->i_sb, &name); - if (res) + res = d_alloc(NULL, &name); + if (res) { + res->d_sb = root_inode->i_sb; + d_set_d_op(res, res->d_sb->s_d_op); + res->d_parent = res; d_instantiate(res, root_inode); + } } return res; } @@ -1496,11 +1566,13 @@ struct dentry *d_obtain_alias(struct inode *inode) if (res) goto out_iput; - tmp = __d_alloc(inode->i_sb, &anonstring); + tmp = d_alloc(NULL, &anonstring); if (!tmp) { res = ERR_PTR(-ENOMEM); goto out_iput; } + tmp->d_parent = tmp; /* make sure dput doesn't croak */ + spin_lock(&inode->i_lock); res = __d_find_any_alias(inode); @@ -1512,6 +1584,8 @@ struct dentry *d_obtain_alias(struct inode *inode) /* attach a disconnected dentry */ spin_lock(&tmp->d_lock); + tmp->d_sb = inode->i_sb; + d_set_d_op(tmp, tmp->d_sb->s_d_op); tmp->d_inode = inode; tmp->d_flags |= DCACHE_DISCONNECTED; list_add(&tmp->d_alias, &inode->i_dentry); @@ -1552,9 +1626,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) { struct dentry *new = NULL; - if (IS_ERR(inode)) - return ERR_CAST(inode); - if (inode && S_ISDIR(inode->i_mode)) { spin_lock(&inode->i_lock); new = __d_find_alias(inode, 1); @@ -1636,23 +1707,30 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, return found; } - /* - * We are going to instantiate this dentry, unhash it and clear the - * lookup flag so we can do that. - */ - if (unlikely(d_need_lookup(found))) - d_clear_need_lookup(found); - /* * Negative dentry: instantiate it unless the inode is a directory and * already has a dentry. */ - new = d_splice_alias(inode, found); - if (new) { - dput(found); - found = new; + spin_lock(&inode->i_lock); + if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) { + __d_instantiate(found, inode); + spin_unlock(&inode->i_lock); + security_d_instantiate(found, inode); + return found; } - return found; + + /* + * In case a directory already has a (disconnected) entry grab a + * reference to it, move it in place and use it. + */ + new = list_entry(inode->i_dentry.next, struct dentry, d_alias); + __dget(new); + spin_unlock(&inode->i_lock); + security_d_instantiate(found, inode); + d_move(new, found); + iput(inode); + dput(found); + return new; err_out: iput(inode); @@ -2967,6 +3045,8 @@ static void __init dcache_init(void) */ dentry_cache = KMEM_CACHE(dentry, SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD); + + register_shrinker(&dcache_shrinker); /* Hash may have been set up in dcache_init_early */ if (!hashdist) diff --git a/trunk/fs/direct-io.c b/trunk/fs/direct-io.c index 01d2d9ef609c..ac5f164170e3 100644 --- a/trunk/fs/direct-io.c +++ b/trunk/fs/direct-io.c @@ -135,50 +135,6 @@ struct dio { struct page *pages[DIO_PAGES]; /* page buffer */ }; -static void __inode_dio_wait(struct inode *inode) -{ - wait_queue_head_t *wq = bit_waitqueue(&inode->i_state, __I_DIO_WAKEUP); - DEFINE_WAIT_BIT(q, &inode->i_state, __I_DIO_WAKEUP); - - do { - prepare_to_wait(wq, &q.wait, TASK_UNINTERRUPTIBLE); - if (atomic_read(&inode->i_dio_count)) - schedule(); - } while (atomic_read(&inode->i_dio_count)); - finish_wait(wq, &q.wait); -} - -/** - * inode_dio_wait - wait for outstanding DIO requests to finish - * @inode: inode to wait for - * - * Waits for all pending direct I/O requests to finish so that we can - * proceed with a truncate or equivalent operation. - * - * Must be called under a lock that serializes taking new references - * to i_dio_count, usually by inode->i_mutex. - */ -void inode_dio_wait(struct inode *inode) -{ - if (atomic_read(&inode->i_dio_count)) - __inode_dio_wait(inode); -} -EXPORT_SYMBOL_GPL(inode_dio_wait); - -/* - * inode_dio_done - signal finish of a direct I/O requests - * @inode: inode the direct I/O happens on - * - * This is called once we've finished processing a direct I/O request, - * and is used to wake up callers waiting for direct I/O to be quiesced. - */ -void inode_dio_done(struct inode *inode) -{ - if (atomic_dec_and_test(&inode->i_dio_count)) - wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); -} -EXPORT_SYMBOL_GPL(inode_dio_done); - /* * How many pages are in the queue? */ @@ -293,12 +249,14 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, bool is if (dio->end_io && dio->result) { dio->end_io(dio->iocb, offset, transferred, dio->map_bh.b_private, ret, is_async); - } else { - if (is_async) - aio_complete(dio->iocb, ret, 0); - inode_dio_done(dio->inode); + } else if (is_async) { + aio_complete(dio->iocb, ret, 0); } + if (dio->flags & DIO_LOCKING) + /* lockdep: non-owner release */ + up_read_non_owner(&dio->inode->i_alloc_sem); + return ret; } @@ -1022,6 +980,9 @@ static int do_direct_IO(struct dio *dio) return ret; } +/* + * Releases both i_mutex and i_alloc_sem + */ static ssize_t direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, const struct iovec *iov, loff_t offset, unsigned long nr_segs, @@ -1185,16 +1146,15 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, * For writes this function is called under i_mutex and returns with * i_mutex held, for reads, i_mutex is not held on entry, but it is * taken and dropped again before returning. + * For reads and writes i_alloc_sem is taken in shared mode and released + * on I/O completion (which may happen asynchronously after returning to + * the caller). + * * - if the flags value does NOT contain DIO_LOCKING we don't use any * internal locking but rather rely on the filesystem to synchronize * direct I/O reads/writes versus each other and truncate. - * - * To help with locking against truncate we incremented the i_dio_count - * counter before starting direct I/O, and decrement it once we are done. - * Truncate can wait for it to reach zero to provide exclusion. It is - * expected that filesystem provide exclusion between new direct I/O - * and truncates. For DIO_LOCKING filesystems this is done by i_mutex, - * but other filesystems need to take care of this on their own. + * For reads and writes both i_mutex and i_alloc_sem are not held on + * entry and are never taken. */ ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, @@ -1240,10 +1200,6 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, } } - /* watch out for a 0 len io from a tricksy fs */ - if (rw == READ && end == offset) - return 0; - dio = kmalloc(sizeof(*dio), GFP_KERNEL); retval = -ENOMEM; if (!dio) @@ -1257,7 +1213,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, dio->flags = flags; if (dio->flags & DIO_LOCKING) { - if (rw == READ) { + /* watch out for a 0 len io from a tricksy fs */ + if (rw == READ && end > offset) { struct address_space *mapping = iocb->ki_filp->f_mapping; @@ -1272,12 +1229,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, goto out; } } - } - /* - * Will be decremented at I/O completion time. - */ - atomic_inc(&inode->i_dio_count); + /* + * Will be released at I/O completion, possibly in a + * different thread. + */ + down_read_non_owner(&inode->i_alloc_sem); + } /* * For file extending writes updating i_size before data diff --git a/trunk/fs/ecryptfs/file.c b/trunk/fs/ecryptfs/file.c index c6ac98cf9baa..4ec9eb00a241 100644 --- a/trunk/fs/ecryptfs/file.c +++ b/trunk/fs/ecryptfs/file.c @@ -270,15 +270,14 @@ static int ecryptfs_release(struct inode *inode, struct file *file) } static int -ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +ecryptfs_fsync(struct file *file, int datasync) { int rc = 0; - rc = generic_file_fsync(file, start, end, datasync); + rc = generic_file_fsync(file, datasync); if (rc) goto out; - rc = vfs_fsync_range(ecryptfs_file_to_lower(file), start, end, - datasync); + rc = vfs_fsync(ecryptfs_file_to_lower(file), datasync); out: return rc; } diff --git a/trunk/fs/ecryptfs/inode.c b/trunk/fs/ecryptfs/inode.c index 340c657a108c..7349ade17de6 100644 --- a/trunk/fs/ecryptfs/inode.c +++ b/trunk/fs/ecryptfs/inode.c @@ -147,6 +147,7 @@ static int ecryptfs_interpose(struct dentry *lower_dentry, * @lower_dir_inode: inode of the parent in the lower fs of the new file * @dentry: New file's dentry * @mode: The mode of the new file + * @nd: nameidata of ecryptfs' parent's dentry & vfsmount * * Creates the file in the lower file system. * @@ -154,10 +155,31 @@ static int ecryptfs_interpose(struct dentry *lower_dentry, */ static int ecryptfs_create_underlying_file(struct inode *lower_dir_inode, - struct dentry *dentry, int mode) + struct dentry *dentry, int mode, + struct nameidata *nd) { struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); - return vfs_create(lower_dir_inode, lower_dentry, mode, NULL); + struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); + struct dentry *dentry_save; + struct vfsmount *vfsmount_save; + unsigned int flags_save; + int rc; + + if (nd) { + dentry_save = nd->path.dentry; + vfsmount_save = nd->path.mnt; + flags_save = nd->flags; + nd->path.dentry = lower_dentry; + nd->path.mnt = lower_mnt; + nd->flags &= ~LOOKUP_OPEN; + } + rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd); + if (nd) { + nd->path.dentry = dentry_save; + nd->path.mnt = vfsmount_save; + nd->flags = flags_save; + } + return rc; } /** @@ -175,7 +197,8 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode, */ static int ecryptfs_do_create(struct inode *directory_inode, - struct dentry *ecryptfs_dentry, int mode) + struct dentry *ecryptfs_dentry, int mode, + struct nameidata *nd) { int rc; struct dentry *lower_dentry; @@ -190,7 +213,7 @@ ecryptfs_do_create(struct inode *directory_inode, goto out; } rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode, - ecryptfs_dentry, mode); + ecryptfs_dentry, mode, nd); if (rc) { printk(KERN_ERR "%s: Failure to create dentry in lower fs; " "rc = [%d]\n", __func__, rc); @@ -271,7 +294,7 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, int rc; /* ecryptfs_do_create() calls ecryptfs_interpose() */ - rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode); + rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd); if (unlikely(rc)) { ecryptfs_printk(KERN_WARNING, "Failed to create file in" "lower filesystem\n"); @@ -919,8 +942,10 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) } static int -ecryptfs_permission(struct inode *inode, int mask) +ecryptfs_permission(struct inode *inode, int mask, unsigned int flags) { + if (flags & IPERM_FLAG_RCU) + return -ECHILD; return inode_permission(ecryptfs_inode_to_lower(inode), mask); } diff --git a/trunk/fs/efs/namei.c b/trunk/fs/efs/namei.c index 832b10ded82f..1511bf9e5f80 100644 --- a/trunk/fs/efs/namei.c +++ b/trunk/fs/efs/namei.c @@ -60,11 +60,14 @@ static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { efs_ino_t inodenum; - struct inode *inode = NULL; + struct inode * inode = NULL; inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); - if (inodenum) + if (inodenum) { inode = efs_iget(dir->i_sb, inodenum); + if (IS_ERR(inode)) + return ERR_CAST(inode); + } return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/exec.c b/trunk/fs/exec.c index 842d5700c155..d9576f261815 100644 --- a/trunk/fs/exec.c +++ b/trunk/fs/exec.c @@ -1114,13 +1114,6 @@ int flush_old_exec(struct linux_binprm * bprm) } EXPORT_SYMBOL(flush_old_exec); -void would_dump(struct linux_binprm *bprm, struct file *file) -{ - if (inode_permission(file->f_path.dentry->d_inode, MAY_READ) < 0) - bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; -} -EXPORT_SYMBOL(would_dump); - void setup_new_exec(struct linux_binprm * bprm) { int i, ch; @@ -1160,10 +1153,9 @@ void setup_new_exec(struct linux_binprm * bprm) if (bprm->cred->uid != current_euid() || bprm->cred->gid != current_egid()) { current->pdeath_signal = 0; - } else { - would_dump(bprm, bprm->file); - if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) - set_dumpable(current->mm, suid_dumpable); + } else if (file_permission(bprm->file, MAY_READ) || + bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) { + set_dumpable(current->mm, suid_dumpable); } /* diff --git a/trunk/fs/exofs/file.c b/trunk/fs/exofs/file.c index 491c6c078e7f..45ca323d8363 100644 --- a/trunk/fs/exofs/file.c +++ b/trunk/fs/exofs/file.c @@ -42,19 +42,11 @@ static int exofs_release_file(struct inode *inode, struct file *filp) * Note, in exofs all metadata is written as part of inode, regardless. * The writeout is synchronous */ -static int exofs_file_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int exofs_file_fsync(struct file *filp, int datasync) { - struct inode *inode = filp->f_mapping->host; int ret; - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - - mutex_lock(&inode->i_mutex); ret = sync_inode_metadata(filp->f_mapping->host, 1); - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/exofs/namei.c b/trunk/fs/exofs/namei.c index b54c43775f17..4d70db110cfc 100644 --- a/trunk/fs/exofs/namei.c +++ b/trunk/fs/exofs/namei.c @@ -55,7 +55,12 @@ static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(-ENAMETOOLONG); ino = exofs_inode_by_name(dir, dentry); - inode = ino ? exofs_iget(dir->i_sb, ino) : NULL; + inode = NULL; + if (ino) { + inode = exofs_iget(dir->i_sb, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + } return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/ext2/acl.c b/trunk/fs/ext2/acl.c index bfe651f9ae16..abea5a17c764 100644 --- a/trunk/fs/ext2/acl.c +++ b/trunk/fs/ext2/acl.c @@ -232,11 +232,11 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) } int -ext2_check_acl(struct inode *inode, int mask) +ext2_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; return -EAGAIN; diff --git a/trunk/fs/ext2/acl.h b/trunk/fs/ext2/acl.h index 3ff6cbb9ac44..c939b7b12099 100644 --- a/trunk/fs/ext2/acl.h +++ b/trunk/fs/ext2/acl.h @@ -54,7 +54,7 @@ static inline int ext2_acl_count(size_t size) #ifdef CONFIG_EXT2_FS_POSIX_ACL /* acl.c */ -extern int ext2_check_acl (struct inode *, int); +extern int ext2_check_acl (struct inode *, int, unsigned int); extern int ext2_acl_chmod (struct inode *); extern int ext2_init_acl (struct inode *, struct inode *); diff --git a/trunk/fs/ext2/ext2.h b/trunk/fs/ext2/ext2.h index af9fc89b1b2d..645be9e7ee47 100644 --- a/trunk/fs/ext2/ext2.h +++ b/trunk/fs/ext2/ext2.h @@ -150,8 +150,7 @@ extern void ext2_write_super (struct super_block *); extern const struct file_operations ext2_dir_operations; /* file.c */ -extern int ext2_fsync(struct file *file, loff_t start, loff_t end, - int datasync); +extern int ext2_fsync(struct file *file, int datasync); extern const struct inode_operations ext2_file_inode_operations; extern const struct file_operations ext2_file_operations; extern const struct file_operations ext2_xip_file_operations; diff --git a/trunk/fs/ext2/file.c b/trunk/fs/ext2/file.c index 82e06321de35..49eec9456c5b 100644 --- a/trunk/fs/ext2/file.c +++ b/trunk/fs/ext2/file.c @@ -40,13 +40,13 @@ static int ext2_release_file (struct inode * inode, struct file * filp) return 0; } -int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int ext2_fsync(struct file *file, int datasync) { int ret; struct super_block *sb = file->f_mapping->host->i_sb; struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; - ret = generic_file_fsync(file, start, end, datasync); + ret = generic_file_fsync(file, datasync); if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) { /* We don't really know where the IO error happened... */ ext2_error(sb, __func__, diff --git a/trunk/fs/ext2/inode.c b/trunk/fs/ext2/inode.c index a8a58f63f07c..788e09a07f7e 100644 --- a/trunk/fs/ext2/inode.c +++ b/trunk/fs/ext2/inode.c @@ -843,8 +843,8 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, struct inode *inode = mapping->host; ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - ext2_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, + iov, offset, nr_segs, ext2_get_block, NULL); if (ret < 0 && (rw & WRITE)) ext2_write_failed(mapping, offset + iov_length(iov, nr_segs)); return ret; @@ -1184,8 +1184,6 @@ static int ext2_setsize(struct inode *inode, loff_t newsize) if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return -EPERM; - inode_dio_wait(inode); - if (mapping_is_xip(inode->i_mapping)) error = xip_truncate_page(inode->i_mapping, newsize); else if (test_opt(inode->i_sb, NOBH)) diff --git a/trunk/fs/ext2/namei.c b/trunk/fs/ext2/namei.c index d60b7099e2db..ed5c5d496ee9 100644 --- a/trunk/fs/ext2/namei.c +++ b/trunk/fs/ext2/namei.c @@ -67,11 +67,15 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str inode = NULL; if (ino) { inode = ext2_iget(dir->i_sb, ino); - if (inode == ERR_PTR(-ESTALE)) { - ext2_error(dir->i_sb, __func__, - "deleted inode referenced: %lu", - (unsigned long) ino); - return ERR_PTR(-EIO); + if (IS_ERR(inode)) { + if (PTR_ERR(inode) == -ESTALE) { + ext2_error(dir->i_sb, __func__, + "deleted inode referenced: %lu", + (unsigned long) ino); + return ERR_PTR(-EIO); + } else { + return ERR_CAST(inode); + } } } return d_splice_alias(inode, dentry); diff --git a/trunk/fs/ext3/acl.c b/trunk/fs/ext3/acl.c index edfeb293d4cb..9d021c0d472a 100644 --- a/trunk/fs/ext3/acl.c +++ b/trunk/fs/ext3/acl.c @@ -240,11 +240,11 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, } int -ext3_check_acl(struct inode *inode, int mask) +ext3_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; return -EAGAIN; diff --git a/trunk/fs/ext3/acl.h b/trunk/fs/ext3/acl.h index 597334626de9..5faf8048e906 100644 --- a/trunk/fs/ext3/acl.h +++ b/trunk/fs/ext3/acl.h @@ -54,7 +54,7 @@ static inline int ext3_acl_count(size_t size) #ifdef CONFIG_EXT3_FS_POSIX_ACL /* acl.c */ -extern int ext3_check_acl (struct inode *, int); +extern int ext3_check_acl (struct inode *, int, unsigned int); extern int ext3_acl_chmod (struct inode *); extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); diff --git a/trunk/fs/ext3/fsync.c b/trunk/fs/ext3/fsync.c index 0bcf63adb80a..09b13bb34c94 100644 --- a/trunk/fs/ext3/fsync.c +++ b/trunk/fs/ext3/fsync.c @@ -43,7 +43,7 @@ * inode to disk. */ -int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +int ext3_sync_file(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; struct ext3_inode_info *ei = EXT3_I(inode); @@ -54,17 +54,6 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) if (inode->i_sb->s_flags & MS_RDONLY) return 0; - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - - /* - * Taking the mutex here just to keep consistent with how fsync was - * called previously, however it looks like we don't need to take - * i_mutex at all. - */ - mutex_lock(&inode->i_mutex); - J_ASSERT(ext3_journal_current_handle() == NULL); /* @@ -81,10 +70,8 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) * (they were dirtied by commit). But that's OK - the blocks are * safe in-journal, which is all fsync() needs to ensure. */ - if (ext3_should_journal_data(inode)) { - mutex_unlock(&inode->i_mutex); + if (ext3_should_journal_data(inode)) return ext3_force_commit(inode->i_sb); - } if (datasync) commit_tid = atomic_read(&ei->i_datasync_tid); @@ -104,6 +91,5 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) */ if (needs_barrier) blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/ext3/inode.c b/trunk/fs/ext3/inode.c index 2978a2a17a59..3451d23c3bae 100644 --- a/trunk/fs/ext3/inode.c +++ b/trunk/fs/ext3/inode.c @@ -1816,8 +1816,9 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, } retry: - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - ext3_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, + ext3_get_block, NULL); /* * In case of error extending write may have instantiated a few * blocks outside i_size. Trim these off again. @@ -3215,9 +3216,6 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) ext3_journal_stop(handle); } - if (attr->ia_valid & ATTR_SIZE) - inode_dio_wait(inode); - if (S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { handle_t *handle; diff --git a/trunk/fs/ext3/namei.c b/trunk/fs/ext3/namei.c index c095cf5640c7..34b6d9bfc48a 100644 --- a/trunk/fs/ext3/namei.c +++ b/trunk/fs/ext3/namei.c @@ -1038,11 +1038,15 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str return ERR_PTR(-EIO); } inode = ext3_iget(dir->i_sb, ino); - if (inode == ERR_PTR(-ESTALE)) { - ext3_error(dir->i_sb, __func__, - "deleted inode referenced: %lu", - ino); - return ERR_PTR(-EIO); + if (IS_ERR(inode)) { + if (PTR_ERR(inode) == -ESTALE) { + ext3_error(dir->i_sb, __func__, + "deleted inode referenced: %lu", + ino); + return ERR_PTR(-EIO); + } else { + return ERR_CAST(inode); + } } } return d_splice_alias(inode, dentry); diff --git a/trunk/fs/ext3/super.c b/trunk/fs/ext3/super.c index b57ea2f91269..aad153ef6b78 100644 --- a/trunk/fs/ext3/super.c +++ b/trunk/fs/ext3/super.c @@ -1718,8 +1718,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); - /* enable barriers by default */ - set_opt(sbi->s_mount_opt, BARRIER); set_opt(sbi->s_mount_opt, RESERVATION); if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum, diff --git a/trunk/fs/ext4/acl.c b/trunk/fs/ext4/acl.c index 60d900fcc3db..21eacd7b7d79 100644 --- a/trunk/fs/ext4/acl.c +++ b/trunk/fs/ext4/acl.c @@ -238,11 +238,11 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, } int -ext4_check_acl(struct inode *inode, int mask) +ext4_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; return -EAGAIN; diff --git a/trunk/fs/ext4/acl.h b/trunk/fs/ext4/acl.h index 9d843d5deac4..dec821168fd4 100644 --- a/trunk/fs/ext4/acl.h +++ b/trunk/fs/ext4/acl.h @@ -54,7 +54,7 @@ static inline int ext4_acl_count(size_t size) #ifdef CONFIG_EXT4_FS_POSIX_ACL /* acl.c */ -extern int ext4_check_acl(struct inode *, int); +extern int ext4_check_acl(struct inode *, int, unsigned int); extern int ext4_acl_chmod(struct inode *); extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); diff --git a/trunk/fs/ext4/ext4.h b/trunk/fs/ext4/ext4.h index fa44df879711..1921392cd708 100644 --- a/trunk/fs/ext4/ext4.h +++ b/trunk/fs/ext4/ext4.h @@ -1758,7 +1758,7 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, extern void ext4_htree_free_dir_info(struct dir_private_info *p); /* fsync.c */ -extern int ext4_sync_file(struct file *, loff_t, loff_t, int); +extern int ext4_sync_file(struct file *, int); extern int ext4_flush_completed_IO(struct inode *); /* hash.c */ diff --git a/trunk/fs/ext4/file.c b/trunk/fs/ext4/file.c index ce766f974b1d..2c0972322009 100644 --- a/trunk/fs/ext4/file.c +++ b/trunk/fs/ext4/file.c @@ -236,27 +236,6 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int origin) } offset += file->f_pos; break; - case SEEK_DATA: - /* - * In the generic case the entire file is data, so as long as - * offset isn't at the end of the file then the offset is data. - */ - if (offset >= inode->i_size) { - mutex_unlock(&inode->i_mutex); - return -ENXIO; - } - break; - case SEEK_HOLE: - /* - * There is a virtual hole at the end of the file, so as long as - * offset isn't i_size or larger, return i_size. - */ - if (offset >= inode->i_size) { - mutex_unlock(&inode->i_mutex); - return -ENXIO; - } - offset = inode->i_size; - break; } if (offset < 0 || offset > maxbytes) { diff --git a/trunk/fs/ext4/fsync.c b/trunk/fs/ext4/fsync.c index da3bed3e0c29..ce66d2fe826c 100644 --- a/trunk/fs/ext4/fsync.c +++ b/trunk/fs/ext4/fsync.c @@ -151,32 +151,6 @@ static int ext4_sync_parent(struct inode *inode) return ret; } -/** - * __sync_file - generic_file_fsync without the locking and filemap_write - * @inode: inode to sync - * @datasync: only sync essential metadata if true - * - * This is just generic_file_fsync without the locking. This is needed for - * nojournal mode to make sure this inodes data/metadata makes it to disk - * properly. The i_mutex should be held already. - */ -static int __sync_inode(struct inode *inode, int datasync) -{ - int err; - int ret; - - ret = sync_mapping_buffers(inode->i_mapping); - if (!(inode->i_state & I_DIRTY)) - return ret; - if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) - return ret; - - err = sync_inode_metadata(inode, 1); - if (ret == 0) - ret = err; - return ret; -} - /* * akpm: A new design for ext4_sync_file(). * @@ -191,7 +165,7 @@ static int __sync_inode(struct inode *inode, int datasync) * i_mutex lock is held when entering and exiting this function */ -int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +int ext4_sync_file(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; struct ext4_inode_info *ei = EXT4_I(inode); @@ -204,20 +178,15 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) trace_ext4_sync_file_enter(file, datasync); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - if (inode->i_sb->s_flags & MS_RDONLY) - goto out; + return 0; ret = ext4_flush_completed_IO(inode); if (ret < 0) goto out; if (!journal) { - ret = __sync_inode(inode, datasync); + ret = generic_file_fsync(file, datasync); if (!ret && !list_empty(&inode->i_dentry)) ret = ext4_sync_parent(inode); goto out; @@ -251,7 +220,6 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) if (needs_barrier) blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); out: - mutex_unlock(&inode->i_mutex); trace_ext4_sync_file_exit(inode, ret); return ret; } diff --git a/trunk/fs/ext4/inode.c b/trunk/fs/ext4/inode.c index 678cde834f19..e3126c051006 100644 --- a/trunk/fs/ext4/inode.c +++ b/trunk/fs/ext4/inode.c @@ -3501,8 +3501,10 @@ static ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, offset, nr_segs, ext4_get_block, NULL, NULL, 0); else { - ret = blockdev_direct_IO(rw, iocb, inode, iov, - offset, nr_segs, ext4_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, + inode->i_sb->s_bdev, iov, + offset, nr_segs, + ext4_get_block, NULL); if (unlikely((rw & WRITE) && ret < 0)) { loff_t isize = i_size_read(inode); @@ -3573,7 +3575,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, ssize_t size, void *private, int ret, bool is_async) { - struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; ext4_io_end_t *io_end = iocb->private; struct workqueue_struct *wq; unsigned long flags; @@ -3595,7 +3596,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, out: if (is_async) aio_complete(iocb, ret, 0); - inode_dio_done(inode); return; } @@ -3616,9 +3616,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, /* queue the work to convert unwritten extents to written */ queue_work(wq, &io_end->work); iocb->private = NULL; - - /* XXX: probably should move into the real I/O completion handler */ - inode_dio_done(inode); } static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate) @@ -3751,13 +3748,11 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, EXT4_I(inode)->cur_aio_dio = iocb->private; } - ret = __blockdev_direct_IO(rw, iocb, inode, + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, ext4_get_block_write, - ext4_end_io_dio, - NULL, - DIO_LOCKING | DIO_SKIP_HOLES); + ext4_end_io_dio); if (iocb->private) EXT4_I(inode)->cur_aio_dio = NULL; /* @@ -5356,8 +5351,6 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) } if (attr->ia_valid & ATTR_SIZE) { - inode_dio_wait(inode); - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); @@ -5850,84 +5843,80 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) struct page *page = vmf->page; loff_t size; unsigned long len; - int ret; + int ret = -EINVAL; + void *fsdata; struct file *file = vma->vm_file; struct inode *inode = file->f_path.dentry->d_inode; struct address_space *mapping = inode->i_mapping; - handle_t *handle; - get_block_t *get_block; - int retries = 0; /* - * This check is racy but catches the common case. We rely on - * __block_page_mkwrite() to do a reliable check. + * Get i_alloc_sem to stop truncates messing with the inode. We cannot + * get i_mutex because we are already holding mmap_sem. */ - vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); - /* Delalloc case is easy... */ - if (test_opt(inode->i_sb, DELALLOC) && - !ext4_should_journal_data(inode) && - !ext4_nonda_switch(inode->i_sb)) { - do { - ret = __block_page_mkwrite(vma, vmf, - ext4_da_get_block_prep); - } while (ret == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)); - goto out_ret; + down_read(&inode->i_alloc_sem); + size = i_size_read(inode); + if (page->mapping != mapping || size <= page_offset(page) + || !PageUptodate(page)) { + /* page got truncated from under us? */ + goto out_unlock; } + ret = 0; lock_page(page); - size = i_size_read(inode); - /* Page got truncated from under us? */ - if (page->mapping != mapping || page_offset(page) > size) { - unlock_page(page); - ret = VM_FAULT_NOPAGE; - goto out; + wait_on_page_writeback(page); + if (PageMappedToDisk(page)) { + up_read(&inode->i_alloc_sem); + return VM_FAULT_LOCKED; } if (page->index == size >> PAGE_CACHE_SHIFT) len = size & ~PAGE_CACHE_MASK; else len = PAGE_CACHE_SIZE; + /* - * Return if we have all the buffers mapped. This avoids the need to do - * journal_start/journal_stop which can block and take a long time + * return if we have all the buffers mapped. This avoid + * the need to call write_begin/write_end which does a + * journal_start/journal_stop which can block and take + * long time */ if (page_has_buffers(page)) { if (!walk_page_buffers(NULL, page_buffers(page), 0, len, NULL, ext4_bh_unmapped)) { - /* Wait so that we don't change page under IO */ - wait_on_page_writeback(page); - ret = VM_FAULT_LOCKED; - goto out; + up_read(&inode->i_alloc_sem); + return VM_FAULT_LOCKED; } } unlock_page(page); - /* OK, we need to fill the hole... */ - if (ext4_should_dioread_nolock(inode)) - get_block = ext4_get_block_write; - else - get_block = ext4_get_block; -retry_alloc: - handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode)); - if (IS_ERR(handle)) { + /* + * OK, we need to fill the hole... Do write_begin write_end + * to do block allocation/reservation.We are not holding + * inode.i__mutex here. That allow * parallel write_begin, + * write_end call. lock_page prevent this from happening + * on the same page though + */ + ret = mapping->a_ops->write_begin(file, mapping, page_offset(page), + len, AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); + if (ret < 0) + goto out_unlock; + ret = mapping->a_ops->write_end(file, mapping, page_offset(page), + len, len, page, fsdata); + if (ret < 0) + goto out_unlock; + ret = 0; + + /* + * write_begin/end might have created a dirty page and someone + * could wander in and start the IO. Make sure that hasn't + * happened. + */ + lock_page(page); + wait_on_page_writeback(page); + up_read(&inode->i_alloc_sem); + return VM_FAULT_LOCKED; +out_unlock: + if (ret) ret = VM_FAULT_SIGBUS; - goto out; - } - ret = __block_page_mkwrite(vma, vmf, get_block); - if (!ret && ext4_should_journal_data(inode)) { - if (walk_page_buffers(handle, page_buffers(page), 0, - PAGE_CACHE_SIZE, NULL, do_journal_get_write_access)) { - unlock_page(page); - ret = VM_FAULT_SIGBUS; - goto out; - } - ext4_set_inode_state(inode, EXT4_STATE_JDATA); - } - ext4_journal_stop(handle); - if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry_alloc; -out_ret: - ret = block_page_mkwrite_return(ret); -out: + up_read(&inode->i_alloc_sem); return ret; } diff --git a/trunk/fs/ext4/namei.c b/trunk/fs/ext4/namei.c index 707d605bf769..b754b7721f51 100644 --- a/trunk/fs/ext4/namei.c +++ b/trunk/fs/ext4/namei.c @@ -1037,11 +1037,15 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru return ERR_PTR(-EIO); } inode = ext4_iget(dir->i_sb, ino); - if (inode == ERR_PTR(-ESTALE)) { - EXT4_ERROR_INODE(dir, - "deleted inode referenced: %u", - ino); - return ERR_PTR(-EIO); + if (IS_ERR(inode)) { + if (PTR_ERR(inode) == -ESTALE) { + EXT4_ERROR_INODE(dir, + "deleted inode referenced: %u", + ino); + return ERR_PTR(-EIO); + } else { + return ERR_CAST(inode); + } } } return d_splice_alias(inode, dentry); diff --git a/trunk/fs/fat/fat.h b/trunk/fs/fat/fat.h index a5d3853822e0..8276cc282dec 100644 --- a/trunk/fs/fat/fat.h +++ b/trunk/fs/fat/fat.h @@ -109,7 +109,6 @@ struct msdos_inode_info { int i_attrs; /* unused attribute bits */ loff_t i_pos; /* on-disk position of directory entry or 0 */ struct hlist_node i_fat_hash; /* hash by i_location */ - struct rw_semaphore truncate_lock; /* protect bmap against truncate */ struct inode vfs_inode; }; @@ -310,8 +309,7 @@ extern int fat_setattr(struct dentry * dentry, struct iattr * attr); extern void fat_truncate_blocks(struct inode *inode, loff_t offset); extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); -extern int fat_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync); +extern int fat_file_fsync(struct file *file, int datasync); /* fat/inode.c */ extern void fat_attach(struct inode *inode, loff_t i_pos); diff --git a/trunk/fs/fat/file.c b/trunk/fs/fat/file.c index c118acf16e43..7018e1d8902d 100644 --- a/trunk/fs/fat/file.c +++ b/trunk/fs/fat/file.c @@ -149,12 +149,12 @@ static int fat_file_release(struct inode *inode, struct file *filp) return 0; } -int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) +int fat_file_fsync(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; int res, err; - res = generic_file_fsync(filp, start, end, datasync); + res = generic_file_fsync(filp, datasync); err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping); return res ? res : err; @@ -397,8 +397,6 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) * sequence. */ if (attr->ia_valid & ATTR_SIZE) { - inode_dio_wait(inode); - if (attr->ia_size > inode->i_size) { error = fat_cont_expand(inode, attr->ia_size); if (error || attr->ia_valid == ATTR_SIZE) @@ -431,10 +429,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) } if (attr->ia_valid & ATTR_SIZE) { - down_write(&MSDOS_I(inode)->truncate_lock); truncate_setsize(inode, attr->ia_size); fat_truncate_blocks(inode, attr->ia_size); - up_write(&MSDOS_I(inode)->truncate_lock); } setattr_copy(inode, attr); diff --git a/trunk/fs/fat/inode.c b/trunk/fs/fat/inode.c index 5942fec22c65..cb8d8391ac0b 100644 --- a/trunk/fs/fat/inode.c +++ b/trunk/fs/fat/inode.c @@ -211,8 +211,8 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, * FAT need to use the DIO_LOCKING for avoiding the race * condition of fat_get_block() and ->truncate(). */ - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - fat_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, + iov, offset, nr_segs, fat_get_block, NULL); if (ret < 0 && (rw & WRITE)) fat_write_failed(mapping, offset + iov_length(iov, nr_segs)); @@ -224,9 +224,9 @@ static sector_t _fat_bmap(struct address_space *mapping, sector_t block) sector_t blocknr; /* fat_get_cluster() assumes the requested blocknr isn't truncated. */ - down_read(&MSDOS_I(mapping->host)->truncate_lock); + down_read(&mapping->host->i_alloc_sem); blocknr = generic_block_bmap(mapping, block, fat_get_block); - up_read(&MSDOS_I(mapping->host)->truncate_lock); + up_read(&mapping->host->i_alloc_sem); return blocknr; } @@ -510,8 +510,6 @@ static struct inode *fat_alloc_inode(struct super_block *sb) ei = kmem_cache_alloc(fat_inode_cachep, GFP_NOFS); if (!ei) return NULL; - - init_rwsem(&ei->truncate_lock); return &ei->vfs_inode; } diff --git a/trunk/fs/fat/namei_msdos.c b/trunk/fs/fat/namei_msdos.c index 66e83b845455..3b222dafd15b 100644 --- a/trunk/fs/fat/namei_msdos.c +++ b/trunk/fs/fat/namei_msdos.c @@ -209,20 +209,29 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, int err; lock_super(sb); + err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo); - switch (err) { - case -ENOENT: - inode = NULL; - break; - case 0: - inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); - brelse(sinfo.bh); - break; - default: - inode = ERR_PTR(err); + if (err) { + if (err == -ENOENT) { + inode = NULL; + goto out; + } + goto error; + } + + inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); + brelse(sinfo.bh); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto error; } +out: unlock_super(sb); return d_splice_alias(inode, dentry); + +error: + unlock_super(sb); + return ERR_PTR(err); } /***** Creates a directory entry (name is already formatted). */ diff --git a/trunk/fs/fat/namei_vfat.c b/trunk/fs/fat/namei_vfat.c index bb3f29c3557b..20b4ea53fdc4 100644 --- a/trunk/fs/fat/namei_vfat.c +++ b/trunk/fs/fat/namei_vfat.c @@ -82,8 +82,10 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) * case sensitive name which is specified by user if this is * for creation. */ - if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) - return 0; + if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { + if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + } return vfat_revalidate_shortname(dentry); } diff --git a/trunk/fs/fs-writeback.c b/trunk/fs/fs-writeback.c index b8c507ca42f7..0f015a0468de 100644 --- a/trunk/fs/fs-writeback.c +++ b/trunk/fs/fs-writeback.c @@ -460,6 +460,32 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) return ret; } +/* + * For background writeback the caller does not have the sb pinned + * before calling writeback. So make sure that we do pin it, so it doesn't + * go away while we are writing inodes from it. + */ +static bool pin_sb_for_writeback(struct super_block *sb) +{ + spin_lock(&sb_lock); + if (list_empty(&sb->s_instances)) { + spin_unlock(&sb_lock); + return false; + } + + sb->s_count++; + spin_unlock(&sb_lock); + + if (down_read_trylock(&sb->s_umount)) { + if (sb->s_root) + return true; + up_read(&sb->s_umount); + } + + put_super(sb); + return false; +} + /* * Write a portion of b_io inodes which belong to @sb. * @@ -559,7 +585,7 @@ void writeback_inodes_wb(struct bdi_writeback *wb, struct inode *inode = wb_inode(wb->b_io.prev); struct super_block *sb = inode->i_sb; - if (!grab_super_passive(sb)) { + if (!pin_sb_for_writeback(sb)) { requeue_io(inode); continue; } diff --git a/trunk/fs/fuse/dir.c b/trunk/fs/fuse/dir.c index 9f63e493a9b6..d50160714595 100644 --- a/trunk/fs/fuse/dir.c +++ b/trunk/fs/fuse/dir.c @@ -382,7 +382,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, struct fuse_entry_out outentry; struct fuse_file *ff; struct file *file; - int flags = nd->intent.open.flags; + int flags = nd->intent.open.flags - 1; if (fc->no_create) return -ENOSYS; @@ -576,7 +576,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, static int fuse_create(struct inode *dir, struct dentry *entry, int mode, struct nameidata *nd) { - if (nd) { + if (nd && (nd->flags & LOOKUP_OPEN)) { int err = fuse_create_open(dir, entry, mode, nd); if (err != -ENOSYS) return err; @@ -971,9 +971,9 @@ static int fuse_access(struct inode *inode, int mask) return err; } -static int fuse_perm_getattr(struct inode *inode, int mask) +static int fuse_perm_getattr(struct inode *inode, int flags) { - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; return fuse_do_getattr(inode, NULL, NULL); @@ -992,7 +992,7 @@ static int fuse_perm_getattr(struct inode *inode, int mask) * access request is sent. Execute permission is still checked * locally based on file mode. */ -static int fuse_permission(struct inode *inode, int mask) +static int fuse_permission(struct inode *inode, int mask, unsigned int flags) { struct fuse_conn *fc = get_fuse_conn(inode); bool refreshed = false; @@ -1011,22 +1011,23 @@ static int fuse_permission(struct inode *inode, int mask) if (fi->i_time < get_jiffies_64()) { refreshed = true; - err = fuse_perm_getattr(inode, mask); + err = fuse_perm_getattr(inode, flags); if (err) return err; } } if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { - err = generic_permission(inode, mask); + err = generic_permission(inode, mask, flags, NULL); /* If permission is denied, try to refresh file attributes. This is also needed, because the root node will at first have no permissions */ if (err == -EACCES && !refreshed) { - err = fuse_perm_getattr(inode, mask); + err = fuse_perm_getattr(inode, flags); if (!err) - err = generic_permission(inode, mask); + err = generic_permission(inode, mask, + flags, NULL); } /* Note: the opposite of the above test does not @@ -1034,7 +1035,7 @@ static int fuse_permission(struct inode *inode, int mask) noticed immediately, only after the attribute timeout has expired */ } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; err = fuse_access(inode, mask); @@ -1043,7 +1044,7 @@ static int fuse_permission(struct inode *inode, int mask) if (refreshed) return -EACCES; - err = fuse_perm_getattr(inode, mask); + err = fuse_perm_getattr(inode, flags); if (!err && !(inode->i_mode & S_IXUGO)) return -EACCES; } @@ -1176,10 +1177,9 @@ static int fuse_dir_release(struct inode *inode, struct file *file) return 0; } -static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int fuse_dir_fsync(struct file *file, int datasync) { - return fuse_fsync_common(file, start, end, datasync, 1); + return fuse_fsync_common(file, datasync, 1); } static bool update_mtime(unsigned ivalid) diff --git a/trunk/fs/fuse/file.c b/trunk/fs/fuse/file.c index 7bb685cdd00c..82a66466a24c 100644 --- a/trunk/fs/fuse/file.c +++ b/trunk/fs/fuse/file.c @@ -400,8 +400,7 @@ static void fuse_sync_writes(struct inode *inode) fuse_release_nowrite(inode); } -int fuse_fsync_common(struct file *file, loff_t start, loff_t end, - int datasync, int isdir) +int fuse_fsync_common(struct file *file, int datasync, int isdir) { struct inode *inode = file->f_mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); @@ -413,15 +412,9 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, if (is_bad_inode(inode)) return -EIO; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) return 0; - mutex_lock(&inode->i_mutex); - /* * Start writeback against all dirty pages of the inode, then * wait for all outstanding writes, before sending the FSYNC @@ -429,15 +422,13 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, */ err = write_inode_now(inode, 0); if (err) - goto out; + return err; fuse_sync_writes(inode); req = fuse_get_req(fc); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto out; - } + if (IS_ERR(req)) + return PTR_ERR(req); memset(&inarg, 0, sizeof(inarg)); inarg.fh = ff->fh; @@ -457,15 +448,12 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, fc->no_fsync = 1; err = 0; } -out: - mutex_unlock(&inode->i_mutex); return err; } -static int fuse_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int fuse_fsync(struct file *file, int datasync) { - return fuse_fsync_common(file, start, end, datasync, 0); + return fuse_fsync_common(file, datasync, 0); } void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos, @@ -1612,32 +1600,15 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin) struct inode *inode = file->f_path.dentry->d_inode; mutex_lock(&inode->i_mutex); - if (origin != SEEK_CUR || origin != SEEK_SET) { + switch (origin) { + case SEEK_END: retval = fuse_update_attributes(inode, NULL, file, NULL); if (retval) goto exit; - } - - switch (origin) { - case SEEK_END: offset += i_size_read(inode); break; case SEEK_CUR: offset += file->f_pos; - break; - case SEEK_DATA: - if (offset >= i_size_read(inode)) { - retval = -ENXIO; - goto exit; - } - break; - case SEEK_HOLE: - if (offset >= i_size_read(inode)) { - retval = -ENXIO; - goto exit; - } - offset = i_size_read(inode); - break; } retval = -EINVAL; if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { diff --git a/trunk/fs/fuse/fuse_i.h b/trunk/fs/fuse/fuse_i.h index c6aa2d4b8517..b788becada76 100644 --- a/trunk/fs/fuse/fuse_i.h +++ b/trunk/fs/fuse/fuse_i.h @@ -589,8 +589,7 @@ void fuse_release_common(struct file *file, int opcode); /** * Send FSYNC or FSYNCDIR request */ -int fuse_fsync_common(struct file *file, loff_t start, loff_t end, - int datasync, int isdir); +int fuse_fsync_common(struct file *file, int datasync, int isdir); /** * Notify poll wakeup diff --git a/trunk/fs/generic_acl.c b/trunk/fs/generic_acl.c index 70e90b4974ce..8f26d1a58912 100644 --- a/trunk/fs/generic_acl.c +++ b/trunk/fs/generic_acl.c @@ -190,9 +190,9 @@ generic_acl_chmod(struct inode *inode) } int -generic_check_acl(struct inode *inode, int mask) +generic_check_acl(struct inode *inode, int mask, unsigned int flags) { - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; } else { diff --git a/trunk/fs/gfs2/acl.c b/trunk/fs/gfs2/acl.c index 8ef1079f1665..cbc07155b1a0 100644 --- a/trunk/fs/gfs2/acl.c +++ b/trunk/fs/gfs2/acl.c @@ -75,12 +75,12 @@ static struct posix_acl *gfs2_acl_get(struct gfs2_inode *ip, int type) * Returns: errno */ -int gfs2_check_acl(struct inode *inode, int mask) +int gfs2_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; int error; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; return -EAGAIN; diff --git a/trunk/fs/gfs2/acl.h b/trunk/fs/gfs2/acl.h index b522b0cb39ea..a93907c8159b 100644 --- a/trunk/fs/gfs2/acl.h +++ b/trunk/fs/gfs2/acl.h @@ -16,7 +16,7 @@ #define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" #define GFS2_ACL_MAX_ENTRIES 25 -extern int gfs2_check_acl(struct inode *inode, int mask); +extern int gfs2_check_acl(struct inode *inode, int mask, unsigned int); extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode); extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); extern const struct xattr_handler gfs2_xattr_system_handler; diff --git a/trunk/fs/gfs2/bmap.c b/trunk/fs/gfs2/bmap.c index 7878c473ae62..42e477f31223 100644 --- a/trunk/fs/gfs2/bmap.c +++ b/trunk/fs/gfs2/bmap.c @@ -1216,8 +1216,6 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize) if (ret) return ret; - inode_dio_wait(inode); - oldsize = inode->i_size; if (newsize >= oldsize) return do_grow(inode, newsize); diff --git a/trunk/fs/gfs2/file.c b/trunk/fs/gfs2/file.c index edeb9e802903..bc2590ef5fc1 100644 --- a/trunk/fs/gfs2/file.c +++ b/trunk/fs/gfs2/file.c @@ -245,7 +245,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) !capable(CAP_LINUX_IMMUTABLE)) goto out; if (!IS_IMMUTABLE(inode)) { - error = gfs2_permission(inode, MAY_WRITE); + error = gfs2_permission(inode, MAY_WRITE, 0); if (error) goto out; } @@ -546,9 +546,7 @@ static int gfs2_close(struct inode *inode, struct file *file) /** * gfs2_fsync - sync the dirty data for a file (across the cluster) - * @file: the file that points to the dentry - * @start: the start position in the file to sync - * @end: the end position in the file to sync + * @file: the file that points to the dentry (we ignore this) * @datasync: set if we can ignore timestamp changes * * The VFS will flush data for us. We only need to worry @@ -557,32 +555,23 @@ static int gfs2_close(struct inode *inode, struct file *file) * Returns: errno */ -static int gfs2_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int gfs2_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC); struct gfs2_inode *ip = GFS2_I(inode); int ret; - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - if (datasync) sync_state &= ~I_DIRTY_SYNC; if (sync_state) { ret = sync_inode_metadata(inode, 1); - if (ret) { - mutex_unlock(&inode->i_mutex); + if (ret) return ret; - } gfs2_ail_flush(ip->i_gl); } - mutex_unlock(&inode->i_mutex); return 0; } diff --git a/trunk/fs/gfs2/inode.c b/trunk/fs/gfs2/inode.c index 0fb51a96eff0..03e0c529063e 100644 --- a/trunk/fs/gfs2/inode.c +++ b/trunk/fs/gfs2/inode.c @@ -307,7 +307,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, } if (!is_root) { - error = gfs2_permission(dir, MAY_EXEC); + error = gfs2_permission(dir, MAY_EXEC, 0); if (error) goto out; } @@ -337,7 +337,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, { int error; - error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); + error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); if (error) return error; @@ -792,8 +792,13 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - struct inode *inode = gfs2_lookupi(dir, &dentry->d_name, 0); - if (inode && !IS_ERR(inode)) { + struct inode *inode = NULL; + + inode = gfs2_lookupi(dir, &dentry->d_name, 0); + if (inode && IS_ERR(inode)) + return ERR_CAST(inode); + + if (inode) { struct gfs2_glock *gl = GFS2_I(inode)->i_gl; struct gfs2_holder gh; int error; @@ -803,8 +808,11 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(error); } gfs2_glock_dq_uninit(&gh); + return d_splice_alias(inode, dentry); } - return d_splice_alias(inode, dentry); + d_add(dentry, inode); + + return NULL; } /** @@ -849,7 +857,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (inode->i_nlink == 0) goto out_gunlock; - error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC); + error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0); if (error) goto out_gunlock; @@ -982,7 +990,7 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, if (IS_APPEND(&dip->i_inode)) return -EPERM; - error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); + error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); if (error) return error; @@ -1328,7 +1336,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, } } } else { - error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC); + error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC, 0); if (error) goto out_gunlock; @@ -1363,7 +1371,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, /* Check out the dir to be renamed */ if (dir_rename) { - error = gfs2_permission(odentry->d_inode, MAY_WRITE); + error = gfs2_permission(odentry->d_inode, MAY_WRITE, 0); if (error) goto out_gunlock; } @@ -1535,7 +1543,7 @@ static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p) * Returns: errno */ -int gfs2_permission(struct inode *inode, int mask) +int gfs2_permission(struct inode *inode, int mask, unsigned int flags) { struct gfs2_inode *ip; struct gfs2_holder i_gh; @@ -1545,7 +1553,7 @@ int gfs2_permission(struct inode *inode, int mask) ip = GFS2_I(inode); if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) @@ -1556,7 +1564,7 @@ int gfs2_permission(struct inode *inode, int mask) if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) error = -EACCES; else - error = generic_permission(inode, mask); + error = generic_permission(inode, mask, flags, gfs2_check_acl); if (unlock) gfs2_glock_dq_uninit(&i_gh); @@ -1846,7 +1854,6 @@ const struct inode_operations gfs2_file_iops = { .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, - .check_acl = gfs2_check_acl, }; const struct inode_operations gfs2_dir_iops = { @@ -1867,7 +1874,6 @@ const struct inode_operations gfs2_dir_iops = { .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, - .check_acl = gfs2_check_acl, }; const struct inode_operations gfs2_symlink_iops = { @@ -1882,6 +1888,5 @@ const struct inode_operations gfs2_symlink_iops = { .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr, .fiemap = gfs2_fiemap, - .check_acl = gfs2_check_acl, }; diff --git a/trunk/fs/gfs2/inode.h b/trunk/fs/gfs2/inode.h index 8d90e0c07672..31606076f701 100644 --- a/trunk/fs/gfs2/inode.h +++ b/trunk/fs/gfs2/inode.h @@ -108,7 +108,7 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip); extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, int is_root); -extern int gfs2_permission(struct inode *inode, int mask); +extern int gfs2_permission(struct inode *inode, int mask, unsigned int flags); extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); diff --git a/trunk/fs/hfs/inode.c b/trunk/fs/hfs/inode.c index 96a1b625fc74..fff16c968e67 100644 --- a/trunk/fs/hfs/inode.c +++ b/trunk/fs/hfs/inode.c @@ -123,8 +123,8 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - hfs_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, hfs_get_block, NULL); /* * In case of error extending write may have instantiated a few @@ -615,8 +615,6 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size != i_size_read(inode)) { - inode_dio_wait(inode); - error = vmtruncate(inode, attr->ia_size); if (error) return error; @@ -627,18 +625,12 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) return 0; } -static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int hfs_file_fsync(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; struct super_block * sb; int ret, err; - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - /* sync the inode to buffers */ ret = write_inode_now(inode, 0); @@ -655,7 +647,6 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end, err = sync_blockdev(sb->s_bdev); if (!ret) ret = err; - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/hfsplus/hfsplus_fs.h b/trunk/fs/hfsplus/hfsplus_fs.h index d7674d051f52..81dfd1e495e3 100644 --- a/trunk/fs/hfsplus/hfsplus_fs.h +++ b/trunk/fs/hfsplus/hfsplus_fs.h @@ -404,8 +404,7 @@ int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *); int hfsplus_cat_write_inode(struct inode *); struct inode *hfsplus_new_inode(struct super_block *, int); void hfsplus_delete_inode(struct inode *); -int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync); +int hfsplus_file_fsync(struct file *file, int datasync); /* ioctl.c */ long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/trunk/fs/hfsplus/inode.c b/trunk/fs/hfsplus/inode.c index 4cc1e3a36ec7..010cd363d085 100644 --- a/trunk/fs/hfsplus/inode.c +++ b/trunk/fs/hfsplus/inode.c @@ -119,8 +119,8 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - hfsplus_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, hfsplus_get_block, NULL); /* * In case of error extending write may have instantiated a few @@ -298,8 +298,6 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size != i_size_read(inode)) { - inode_dio_wait(inode); - error = vmtruncate(inode, attr->ia_size); if (error) return error; @@ -310,19 +308,13 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) return 0; } -int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +int hfsplus_file_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; struct hfsplus_inode_info *hip = HFSPLUS_I(inode); struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); int error = 0, error2; - error = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (error) - return error; - mutex_lock(&inode->i_mutex); - /* * Sync inode metadata into the catalog and extent trees. */ @@ -350,8 +342,6 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); - mutex_unlock(&inode->i_mutex); - return error; } diff --git a/trunk/fs/hostfs/hostfs_kern.c b/trunk/fs/hostfs/hostfs_kern.c index 0d22afdd4611..2638c834ed28 100644 --- a/trunk/fs/hostfs/hostfs_kern.c +++ b/trunk/fs/hostfs/hostfs_kern.c @@ -362,20 +362,9 @@ int hostfs_file_open(struct inode *ino, struct file *file) return 0; } -int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int hostfs_fsync(struct file *file, int datasync) { - struct inode *inode = file->f_mapping->host; - int ret; - - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - - mutex_lock(&inode->i_mutex); - ret = fsync_file(HOSTFS_I(inode)->fd, datasync); - mutex_unlock(&inode->i_mutex); - - return ret; + return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync); } static const struct file_operations hostfs_file_fops = { @@ -759,12 +748,12 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from, return err; } -int hostfs_permission(struct inode *ino, int desired) +int hostfs_permission(struct inode *ino, int desired, unsigned int flags) { char *name; int r = 0, w = 0, x = 0, err; - if (desired & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; if (desired & MAY_READ) r = 1; @@ -781,7 +770,7 @@ int hostfs_permission(struct inode *ino, int desired) err = access_file(name, r, w, x); __putname(name); if (!err) - err = generic_permission(ino, desired); + err = generic_permission(ino, desired, flags, NULL); return err; } diff --git a/trunk/fs/hpfs/dir.c b/trunk/fs/hpfs/dir.c index 96a8ed91cedd..f46ae025bfb5 100644 --- a/trunk/fs/hpfs/dir.c +++ b/trunk/fs/hpfs/dir.c @@ -29,10 +29,6 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence) struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct super_block *s = i->i_sb; - /* Somebody else will have to figure out what to do here */ - if (whence == SEEK_DATA || whence == SEEK_HOLE) - return -EINVAL; - hpfs_lock(s); /*printk("dir lseek\n");*/ diff --git a/trunk/fs/hpfs/file.c b/trunk/fs/hpfs/file.c index 89d2a5803ae3..89c500ee5213 100644 --- a/trunk/fs/hpfs/file.c +++ b/trunk/fs/hpfs/file.c @@ -18,14 +18,9 @@ static int hpfs_file_release(struct inode *inode, struct file *file) return 0; } -int hpfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int hpfs_file_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; - int ret; - - ret = filemap_write_and_wait_range(file->f_mapping, start, end); - if (ret) - return ret; return sync_blockdev(inode->i_sb->s_bdev); } diff --git a/trunk/fs/hpfs/hpfs_fn.h b/trunk/fs/hpfs/hpfs_fn.h index 331b5e234ef3..dd552f862c8f 100644 --- a/trunk/fs/hpfs/hpfs_fn.h +++ b/trunk/fs/hpfs/hpfs_fn.h @@ -258,7 +258,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, const char *, /* file.c */ -int hpfs_file_fsync(struct file *, loff_t, loff_t, int); +int hpfs_file_fsync(struct file *, int); extern const struct file_operations hpfs_file_ops; extern const struct inode_operations hpfs_file_iops; extern const struct address_space_operations hpfs_aops; diff --git a/trunk/fs/hpfs/namei.c b/trunk/fs/hpfs/namei.c index 2df69e2f07cf..acf95dab2aac 100644 --- a/trunk/fs/hpfs/namei.c +++ b/trunk/fs/hpfs/namei.c @@ -398,7 +398,7 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry) hpfs_unlock(dir->i_sb); return -ENOSPC; } - if (generic_permission(inode, MAY_WRITE) || + if (generic_permission(inode, MAY_WRITE, 0, NULL) || !S_ISREG(inode->i_mode) || get_write_access(inode)) { d_rehash(dentry); diff --git a/trunk/fs/hppfs/hppfs.c b/trunk/fs/hppfs/hppfs.c index 8635be5ffd97..85c098a499f3 100644 --- a/trunk/fs/hppfs/hppfs.c +++ b/trunk/fs/hppfs/hppfs.c @@ -573,10 +573,9 @@ static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir) return err; } -static int hppfs_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +static int hppfs_fsync(struct file *file, int datasync) { - return filemap_write_and_wait_range(file->f_mapping, start, end); + return 0; } static const struct file_operations hppfs_dir_fops = { diff --git a/trunk/fs/inode.c b/trunk/fs/inode.c index 96c77b81167c..43566d17d1b8 100644 --- a/trunk/fs/inode.c +++ b/trunk/fs/inode.c @@ -33,8 +33,8 @@ * * inode->i_lock protects: * inode->i_state, inode->i_hash, __iget() - * inode->i_sb->s_inode_lru_lock protects: - * inode->i_sb->s_inode_lru, inode->i_lru + * inode_lru_lock protects: + * inode_lru, inode->i_lru * inode_sb_list_lock protects: * sb->s_inodes, inode->i_sb_list * inode_wb_list_lock protects: @@ -46,7 +46,7 @@ * * inode_sb_list_lock * inode->i_lock - * inode->i_sb->s_inode_lru_lock + * inode_lru_lock * * inode_wb_list_lock * inode->i_lock @@ -64,9 +64,23 @@ static unsigned int i_hash_shift __read_mostly; static struct hlist_head *inode_hashtable __read_mostly; static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock); +static LIST_HEAD(inode_lru); +static DEFINE_SPINLOCK(inode_lru_lock); + __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_sb_list_lock); __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_wb_list_lock); +/* + * iprune_sem provides exclusion between the icache shrinking and the + * umount path. + * + * We don't actually need it to protect anything in the umount path, + * but only need to cycle through it to make sure any inode that + * prune_icache took off the LRU list has been fully torn down by the + * time we are past evict_inodes. + */ +static DECLARE_RWSEM(iprune_sem); + /* * Empty aops. Can be used for the cases where the user does not * define any of the address_space operations. @@ -81,7 +95,6 @@ EXPORT_SYMBOL(empty_aops); struct inodes_stat_t inodes_stat; static DEFINE_PER_CPU(unsigned int, nr_inodes); -static DEFINE_PER_CPU(unsigned int, nr_unused); static struct kmem_cache *inode_cachep __read_mostly; @@ -96,11 +109,7 @@ static int get_nr_inodes(void) static inline int get_nr_inodes_unused(void) { - int i; - int sum = 0; - for_each_possible_cpu(i) - sum += per_cpu(nr_unused, i); - return sum < 0 ? 0 : sum; + return inodes_stat.nr_unused; } int get_nr_dirty_inodes(void) @@ -118,7 +127,6 @@ int proc_nr_inodes(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { inodes_stat.nr_inodes = get_nr_inodes(); - inodes_stat.nr_unused = get_nr_inodes_unused(); return proc_dointvec(table, write, buffer, lenp, ppos); } #endif @@ -168,7 +176,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode) mutex_init(&inode->i_mutex); lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key); - atomic_set(&inode->i_dio_count, 0); + init_rwsem(&inode->i_alloc_sem); + lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key); mapping->a_ops = &empty_aops; mapping->host = inode; @@ -328,24 +337,22 @@ EXPORT_SYMBOL(ihold); static void inode_lru_list_add(struct inode *inode) { - spin_lock(&inode->i_sb->s_inode_lru_lock); + spin_lock(&inode_lru_lock); if (list_empty(&inode->i_lru)) { - list_add(&inode->i_lru, &inode->i_sb->s_inode_lru); - inode->i_sb->s_nr_inodes_unused++; - this_cpu_inc(nr_unused); + list_add(&inode->i_lru, &inode_lru); + inodes_stat.nr_unused++; } - spin_unlock(&inode->i_sb->s_inode_lru_lock); + spin_unlock(&inode_lru_lock); } static void inode_lru_list_del(struct inode *inode) { - spin_lock(&inode->i_sb->s_inode_lru_lock); + spin_lock(&inode_lru_lock); if (!list_empty(&inode->i_lru)) { list_del_init(&inode->i_lru); - inode->i_sb->s_nr_inodes_unused--; - this_cpu_dec(nr_unused); + inodes_stat.nr_unused--; } - spin_unlock(&inode->i_sb->s_inode_lru_lock); + spin_unlock(&inode_lru_lock); } /** @@ -530,6 +537,14 @@ void evict_inodes(struct super_block *sb) spin_unlock(&inode_sb_list_lock); dispose_list(&dispose); + + /* + * Cycle through iprune_sem to make sure any inode that prune_icache + * moved off the list before we took the lock has been fully torn + * down. + */ + down_write(&iprune_sem); + up_write(&iprune_sem); } /** @@ -592,10 +607,8 @@ static int can_unuse(struct inode *inode) } /* - * Walk the superblock inode LRU for freeable inodes and attempt to free them. - * This is called from the superblock shrinker function with a number of inodes - * to trim from the LRU. Inodes to be freed are moved to a temporary list and - * then are freed outside inode_lock by dispose_list(). + * Scan `goal' inodes on the unused list for freeable ones. They are moved to a + * temporary list and then are freed outside inode_lru_lock by dispose_list(). * * Any inodes which are pinned purely because of attached pagecache have their * pagecache removed. If the inode has metadata buffers attached to @@ -609,28 +622,29 @@ static int can_unuse(struct inode *inode) * LRU does not have strict ordering. Hence we don't want to reclaim inodes * with this flag set because they are the inodes that are out of order. */ -void prune_icache_sb(struct super_block *sb, int nr_to_scan) +static void prune_icache(int nr_to_scan) { LIST_HEAD(freeable); int nr_scanned; unsigned long reap = 0; - spin_lock(&sb->s_inode_lru_lock); - for (nr_scanned = nr_to_scan; nr_scanned >= 0; nr_scanned--) { + down_read(&iprune_sem); + spin_lock(&inode_lru_lock); + for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) { struct inode *inode; - if (list_empty(&sb->s_inode_lru)) + if (list_empty(&inode_lru)) break; - inode = list_entry(sb->s_inode_lru.prev, struct inode, i_lru); + inode = list_entry(inode_lru.prev, struct inode, i_lru); /* - * we are inverting the sb->s_inode_lru_lock/inode->i_lock here, + * we are inverting the inode_lru_lock/inode->i_lock here, * so use a trylock. If we fail to get the lock, just move the * inode to the back of the list so we don't spin on it. */ if (!spin_trylock(&inode->i_lock)) { - list_move(&inode->i_lru, &sb->s_inode_lru); + list_move(&inode->i_lru, &inode_lru); continue; } @@ -642,29 +656,28 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan) (inode->i_state & ~I_REFERENCED)) { list_del_init(&inode->i_lru); spin_unlock(&inode->i_lock); - sb->s_nr_inodes_unused--; - this_cpu_dec(nr_unused); + inodes_stat.nr_unused--; continue; } /* recently referenced inodes get one more pass */ if (inode->i_state & I_REFERENCED) { inode->i_state &= ~I_REFERENCED; - list_move(&inode->i_lru, &sb->s_inode_lru); + list_move(&inode->i_lru, &inode_lru); spin_unlock(&inode->i_lock); continue; } if (inode_has_buffers(inode) || inode->i_data.nrpages) { __iget(inode); spin_unlock(&inode->i_lock); - spin_unlock(&sb->s_inode_lru_lock); + spin_unlock(&inode_lru_lock); if (remove_inode_buffers(inode)) reap += invalidate_mapping_pages(&inode->i_data, 0, -1); iput(inode); - spin_lock(&sb->s_inode_lru_lock); + spin_lock(&inode_lru_lock); - if (inode != list_entry(sb->s_inode_lru.next, + if (inode != list_entry(inode_lru.next, struct inode, i_lru)) continue; /* wrong inode or list_empty */ /* avoid lock inversions with trylock */ @@ -680,18 +693,51 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan) spin_unlock(&inode->i_lock); list_move(&inode->i_lru, &freeable); - sb->s_nr_inodes_unused--; - this_cpu_dec(nr_unused); + inodes_stat.nr_unused--; } if (current_is_kswapd()) __count_vm_events(KSWAPD_INODESTEAL, reap); else __count_vm_events(PGINODESTEAL, reap); - spin_unlock(&sb->s_inode_lru_lock); + spin_unlock(&inode_lru_lock); dispose_list(&freeable); + up_read(&iprune_sem); } +/* + * shrink_icache_memory() will attempt to reclaim some unused inodes. Here, + * "unused" means that no dentries are referring to the inodes: the files are + * not open and the dcache references to those inodes have already been + * reclaimed. + * + * This function is passed the number of inodes to scan, and it returns the + * total number of remaining possibly-reclaimable inodes. + */ +static int shrink_icache_memory(struct shrinker *shrink, + struct shrink_control *sc) +{ + int nr = sc->nr_to_scan; + gfp_t gfp_mask = sc->gfp_mask; + + if (nr) { + /* + * Nasty deadlock avoidance. We may hold various FS locks, + * and we don't want to recurse into the FS that called us + * in clear_inode() and friends.. + */ + if (!(gfp_mask & __GFP_FS)) + return -1; + prune_icache(nr); + } + return (get_nr_inodes_unused() / 100) * sysctl_vfs_cache_pressure; +} + +static struct shrinker icache_shrinker = { + .shrink = shrink_icache_memory, + .seeks = DEFAULT_SEEKS, +}; + static void __wait_on_freeing_inode(struct inode *inode); /* * Called with the inode lock held. @@ -1285,7 +1331,7 @@ static void iput_final(struct inode *inode) WARN_ON(inode->i_state & I_NEW); - if (op->drop_inode) + if (op && op->drop_inode) drop = op->drop_inode(inode); else drop = generic_drop_inode(inode); @@ -1571,6 +1617,7 @@ void __init inode_init(void) (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC| SLAB_MEM_SPREAD), init_once); + register_shrinker(&icache_shrinker); /* Hash may have been set up in inode_init_early */ if (!hashdist) diff --git a/trunk/fs/internal.h b/trunk/fs/internal.h index fe327c20af83..b29c46e4e32f 100644 --- a/trunk/fs/internal.h +++ b/trunk/fs/internal.h @@ -97,7 +97,6 @@ extern struct file *get_empty_filp(void); * super.c */ extern int do_remount_sb(struct super_block *, int, void *, int); -extern bool grab_super_passive(struct super_block *sb); extern void __put_super(struct super_block *sb); extern void put_super(struct super_block *sb); extern struct dentry *mount_fs(struct file_system_type *, @@ -136,8 +135,3 @@ extern void inode_wb_list_del(struct inode *inode); extern int get_nr_dirty_inodes(void); extern void evict_inodes(struct super_block *); extern int invalidate_inodes(struct super_block *, bool); - -/* - * dcache.c - */ -extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); diff --git a/trunk/fs/isofs/dir.c b/trunk/fs/isofs/dir.c index f20437c068a0..0542b6eedf80 100644 --- a/trunk/fs/isofs/dir.c +++ b/trunk/fs/isofs/dir.c @@ -254,16 +254,19 @@ static int isofs_readdir(struct file *filp, char *tmpname; struct iso_directory_record *tmpde; struct inode *inode = filp->f_path.dentry->d_inode; + struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb); tmpname = (char *)__get_free_page(GFP_KERNEL); if (tmpname == NULL) return -ENOMEM; + mutex_lock(&sbi->s_mutex); tmpde = (struct iso_directory_record *) (tmpname+1024); result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde); free_page((unsigned long) tmpname); + mutex_unlock(&sbi->s_mutex); return result; } diff --git a/trunk/fs/isofs/inode.c b/trunk/fs/isofs/inode.c index a5d03672d04e..b3cc8586984e 100644 --- a/trunk/fs/isofs/inode.c +++ b/trunk/fs/isofs/inode.c @@ -863,6 +863,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) sbi->s_utf8 = opt.utf8; sbi->s_nocompress = opt.nocompress; sbi->s_overriderockperm = opt.overriderockperm; + mutex_init(&sbi->s_mutex); /* * It would be incredibly stupid to allow people to mark every file * on the disk as suid, so we merely allow them to set the default diff --git a/trunk/fs/isofs/isofs.h b/trunk/fs/isofs/isofs.h index 7d33de84f52a..2882dc089f87 100644 --- a/trunk/fs/isofs/isofs.h +++ b/trunk/fs/isofs/isofs.h @@ -55,6 +55,7 @@ struct isofs_sb_info { gid_t s_gid; uid_t s_uid; struct nls_table *s_nls_iocharset; /* Native language support table */ + struct mutex s_mutex; /* replaces BKL, please remove if possible */ }; #define ISOFS_INVALID_MODE ((mode_t) -1) diff --git a/trunk/fs/isofs/namei.c b/trunk/fs/isofs/namei.c index 1e2946f2a69e..4fb3e8074fd4 100644 --- a/trunk/fs/isofs/namei.c +++ b/trunk/fs/isofs/namei.c @@ -168,6 +168,7 @@ struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nam int found; unsigned long uninitialized_var(block); unsigned long uninitialized_var(offset); + struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb); struct inode *inode; struct page *page; @@ -175,13 +176,21 @@ struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nam if (!page) return ERR_PTR(-ENOMEM); + mutex_lock(&sbi->s_mutex); found = isofs_find_entry(dir, dentry, &block, &offset, page_address(page), 1024 + page_address(page)); __free_page(page); - inode = found ? isofs_iget(dir->i_sb, block, offset) : NULL; - + inode = NULL; + if (found) { + inode = isofs_iget(dir->i_sb, block, offset); + if (IS_ERR(inode)) { + mutex_unlock(&sbi->s_mutex); + return ERR_CAST(inode); + } + } + mutex_unlock(&sbi->s_mutex); return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/isofs/rock.c b/trunk/fs/isofs/rock.c index 1fbc7de88f50..f9cd04db6eab 100644 --- a/trunk/fs/isofs/rock.c +++ b/trunk/fs/isofs/rock.c @@ -678,6 +678,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) init_rock_state(&rs, inode); block = ei->i_iget5_block; + mutex_lock(&sbi->s_mutex); bh = sb_bread(inode->i_sb, block); if (!bh) goto out_noread; @@ -747,6 +748,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) goto fail; brelse(bh); *rpnt = '\0'; + mutex_unlock(&sbi->s_mutex); SetPageUptodate(page); kunmap(page); unlock_page(page); @@ -763,6 +765,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) printk("symlink spans iso9660 blocks\n"); fail: brelse(bh); + mutex_unlock(&sbi->s_mutex); error: SetPageError(page); kunmap(page); diff --git a/trunk/fs/jffs2/acl.c b/trunk/fs/jffs2/acl.c index 3675b3cdee89..828a0e1ea438 100644 --- a/trunk/fs/jffs2/acl.c +++ b/trunk/fs/jffs2/acl.c @@ -259,12 +259,12 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) return rc; } -int jffs2_check_acl(struct inode *inode, int mask) +int jffs2_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; int rc; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); diff --git a/trunk/fs/jffs2/acl.h b/trunk/fs/jffs2/acl.h index 5e42de8d9541..3119f59253d3 100644 --- a/trunk/fs/jffs2/acl.h +++ b/trunk/fs/jffs2/acl.h @@ -26,7 +26,7 @@ struct jffs2_acl_header { #ifdef CONFIG_JFFS2_FS_POSIX_ACL -extern int jffs2_check_acl(struct inode *, int); +extern int jffs2_check_acl(struct inode *, int, unsigned int); extern int jffs2_acl_chmod(struct inode *); extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); extern int jffs2_init_acl_post(struct inode *); diff --git a/trunk/fs/jffs2/dir.c b/trunk/fs/jffs2/dir.c index 5f243cd63afc..4bca6a2e5c07 100644 --- a/trunk/fs/jffs2/dir.c +++ b/trunk/fs/jffs2/dir.c @@ -102,8 +102,10 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, mutex_unlock(&dir_f->sem); if (ino) { inode = jffs2_iget(dir_i->i_sb, ino); - if (IS_ERR(inode)) + if (IS_ERR(inode)) { printk(KERN_WARNING "iget() failed for ino #%u\n", ino); + return ERR_CAST(inode); + } } return d_splice_alias(inode, target); @@ -820,10 +822,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, if (victim_f) { /* There was a victim. Kill it off nicely */ - if (S_ISDIR(new_dentry->d_inode->i_mode)) - clear_nlink(new_dentry->d_inode); - else - drop_nlink(new_dentry->d_inode); + drop_nlink(new_dentry->d_inode); /* Don't oops if the victim was a dirent pointing to an inode which didn't exist. */ if (victim_f->inocache) { diff --git a/trunk/fs/jffs2/file.c b/trunk/fs/jffs2/file.c index 3989f7e09f7f..1c0a08d711aa 100644 --- a/trunk/fs/jffs2/file.c +++ b/trunk/fs/jffs2/file.c @@ -27,20 +27,13 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, struct page **pagep, void **fsdata); static int jffs2_readpage (struct file *filp, struct page *pg); -int jffs2_fsync(struct file *filp, loff_t start, loff_t end, int datasync) +int jffs2_fsync(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - int ret; - - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); /* Trigger GC to flush any pending writes for this inode */ jffs2_flush_wbuf_gc(c, inode->i_ino); - mutex_unlock(&inode->i_mutex); return 0; } diff --git a/trunk/fs/jffs2/os-linux.h b/trunk/fs/jffs2/os-linux.h index 9c252835e8e5..65c6c43ca482 100644 --- a/trunk/fs/jffs2/os-linux.h +++ b/trunk/fs/jffs2/os-linux.h @@ -158,7 +158,7 @@ extern const struct inode_operations jffs2_dir_inode_operations; extern const struct file_operations jffs2_file_operations; extern const struct inode_operations jffs2_file_inode_operations; extern const struct address_space_operations jffs2_file_address_operations; -int jffs2_fsync(struct file *, loff_t, loff_t, int); +int jffs2_fsync(struct file *, int); int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); /* ioctl.c */ diff --git a/trunk/fs/jfs/acl.c b/trunk/fs/jfs/acl.c index 8a0a0666d5a6..e5de9422fa32 100644 --- a/trunk/fs/jfs/acl.c +++ b/trunk/fs/jfs/acl.c @@ -114,11 +114,11 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type, return rc; } -int jfs_check_acl(struct inode *inode, int mask) +int jfs_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); diff --git a/trunk/fs/jfs/file.c b/trunk/fs/jfs/file.c index 7527855b5cc6..2f3f531f3606 100644 --- a/trunk/fs/jfs/file.c +++ b/trunk/fs/jfs/file.c @@ -28,26 +28,19 @@ #include "jfs_acl.h" #include "jfs_debug.h" -int jfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int jfs_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; int rc = 0; - rc = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (rc) - return rc; - - mutex_lock(&inode->i_mutex); if (!(inode->i_state & I_DIRTY) || (datasync && !(inode->i_state & I_DIRTY_DATASYNC))) { /* Make sure committed changes hit the disk */ jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1); - mutex_unlock(&inode->i_mutex); return rc; } rc |= jfs_commit_inode(inode, 1); - mutex_unlock(&inode->i_mutex); return rc ? -EIO : 0; } @@ -117,8 +110,6 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size != i_size_read(inode)) { - inode_dio_wait(inode); - rc = vmtruncate(inode, iattr->ia_size); if (rc) return rc; diff --git a/trunk/fs/jfs/inode.c b/trunk/fs/jfs/inode.c index 77b69b27f825..109655904bbc 100644 --- a/trunk/fs/jfs/inode.c +++ b/trunk/fs/jfs/inode.c @@ -329,8 +329,8 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = file->f_mapping->host; ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - jfs_get_block); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, jfs_get_block, NULL); /* * In case of error extending write may have instantiated a few diff --git a/trunk/fs/jfs/jfs_acl.h b/trunk/fs/jfs/jfs_acl.h index 54e07559878d..f9285c4900fa 100644 --- a/trunk/fs/jfs/jfs_acl.h +++ b/trunk/fs/jfs/jfs_acl.h @@ -20,7 +20,7 @@ #ifdef CONFIG_JFS_POSIX_ACL -int jfs_check_acl(struct inode *, int); +int jfs_check_acl(struct inode *, int, unsigned int flags); int jfs_init_acl(tid_t, struct inode *, struct inode *); int jfs_acl_chmod(struct inode *inode); diff --git a/trunk/fs/jfs/jfs_inode.h b/trunk/fs/jfs/jfs_inode.h index 9271cfe4a149..ec2fb8b945fc 100644 --- a/trunk/fs/jfs/jfs_inode.h +++ b/trunk/fs/jfs/jfs_inode.h @@ -21,7 +21,7 @@ struct fid; extern struct inode *ialloc(struct inode *, umode_t); -extern int jfs_fsync(struct file *, loff_t, loff_t, int); +extern int jfs_fsync(struct file *, int); extern long jfs_ioctl(struct file *, unsigned int, unsigned long); extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long); extern struct inode *jfs_iget(struct super_block *, unsigned long); diff --git a/trunk/fs/jfs/namei.c b/trunk/fs/jfs/namei.c index 03787ef6a118..eaaf2b511e89 100644 --- a/trunk/fs/jfs/namei.c +++ b/trunk/fs/jfs/namei.c @@ -1456,23 +1456,34 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc ino_t inum; struct inode *ip; struct component_name key; + const char *name = dentry->d_name.name; + int len = dentry->d_name.len; int rc; - jfs_info("jfs_lookup: name = %s", dentry->d_name.name); - - if ((rc = get_UCSname(&key, dentry))) - return ERR_PTR(rc); - rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP); - free_UCSname(&key); - if (rc == -ENOENT) { - ip = NULL; - } else if (rc) { - jfs_err("jfs_lookup: dtSearch returned %d", rc); - ip = ERR_PTR(rc); - } else { - ip = jfs_iget(dip->i_sb, inum); - if (IS_ERR(ip)) - jfs_err("jfs_lookup: iget failed on inum %d", (uint)inum); + jfs_info("jfs_lookup: name = %s", name); + + if ((name[0] == '.') && (len == 1)) + inum = dip->i_ino; + else if (strcmp(name, "..") == 0) + inum = PARENT(dip); + else { + if ((rc = get_UCSname(&key, dentry))) + return ERR_PTR(rc); + rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP); + free_UCSname(&key); + if (rc == -ENOENT) { + d_add(dentry, NULL); + return NULL; + } else if (rc) { + jfs_err("jfs_lookup: dtSearch returned %d", rc); + return ERR_PTR(rc); + } + } + + ip = jfs_iget(dip->i_sb, inum); + if (IS_ERR(ip)) { + jfs_err("jfs_lookup: iget failed on inum %d", (uint) inum); + return ERR_CAST(ip); } return d_splice_alias(ip, dentry); @@ -1586,6 +1597,8 @@ static int jfs_ci_compare(const struct dentry *parent, static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd) { + if (nd && nd->flags & LOOKUP_RCU) + return -ECHILD; /* * This is not negative dentry. Always valid. * @@ -1611,8 +1624,10 @@ static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd) * case sensitive name which is specified by user if this is * for creation. */ - if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) - return 0; + if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { + if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + } return 1; } diff --git a/trunk/fs/libfs.c b/trunk/fs/libfs.c index c18e9a1235b6..275ca4749a2e 100644 --- a/trunk/fs/libfs.c +++ b/trunk/fs/libfs.c @@ -16,8 +16,6 @@ #include -#include "internal.h" - static inline int simple_positive(struct dentry *dentry) { return dentry->d_inode && !d_unhashed(dentry); @@ -248,11 +246,13 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name, root->i_ino = 1; root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; - dentry = __d_alloc(s, &d_name); + dentry = d_alloc(NULL, &d_name); if (!dentry) { iput(root); goto Enomem; } + dentry->d_sb = s; + dentry->d_parent = dentry; d_instantiate(dentry, root); s->s_root = dentry; s->s_d_op = dops; @@ -328,10 +328,8 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry, if (new_dentry->d_inode) { simple_unlink(new_dir, new_dentry); - if (they_are_dirs) { - drop_nlink(new_dentry->d_inode); + if (they_are_dirs) drop_nlink(old_dir); - } } else if (they_are_dirs) { drop_nlink(old_dir); inc_nlink(new_dir); @@ -907,29 +905,21 @@ EXPORT_SYMBOL_GPL(generic_fh_to_parent); * filesystems which track all non-inode metadata in the buffers list * hanging off the address_space structure. */ -int generic_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +int generic_file_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; int err; int ret; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - mutex_lock(&inode->i_mutex); ret = sync_mapping_buffers(inode->i_mapping); if (!(inode->i_state & I_DIRTY)) - goto out; + return ret; if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) - goto out; + return ret; err = sync_inode_metadata(inode, 1); if (ret == 0) ret = err; -out: - mutex_unlock(&inode->i_mutex); return ret; } EXPORT_SYMBOL(generic_file_fsync); @@ -966,7 +956,7 @@ EXPORT_SYMBOL(generic_check_addressable); /* * No-op implementation of ->fsync for in-memory filesystems. */ -int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int noop_fsync(struct file *file, int datasync) { return 0; } diff --git a/trunk/fs/logfs/dir.c b/trunk/fs/logfs/dir.c index b3ff3d894165..1afae26cf236 100644 --- a/trunk/fs/logfs/dir.c +++ b/trunk/fs/logfs/dir.c @@ -371,9 +371,11 @@ static struct dentry *logfs_lookup(struct inode *dir, struct dentry *dentry, page_cache_release(page); inode = logfs_iget(dir->i_sb, ino); - if (IS_ERR(inode)) + if (IS_ERR(inode)) { printk(KERN_ERR"LogFS: Cannot read inode #%llx for dentry (%lx, %lx)n", ino, dir->i_ino, index); + return ERR_CAST(inode); + } return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/logfs/file.c b/trunk/fs/logfs/file.c index b548c87a86f1..c2ad7028def4 100644 --- a/trunk/fs/logfs/file.c +++ b/trunk/fs/logfs/file.c @@ -219,20 +219,11 @@ long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } } -int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int logfs_fsync(struct file *file, int datasync) { struct super_block *sb = file->f_mapping->host->i_sb; - struct inode *inode = file->f_mapping->host; - int ret; - - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); logfs_write_anchor(sb); - mutex_unlock(&inode->i_mutex); - return 0; } diff --git a/trunk/fs/logfs/logfs.h b/trunk/fs/logfs/logfs.h index f22d108bfa5d..57afd4a6fabb 100644 --- a/trunk/fs/logfs/logfs.h +++ b/trunk/fs/logfs/logfs.h @@ -506,7 +506,7 @@ extern const struct file_operations logfs_reg_fops; extern const struct address_space_operations logfs_reg_aops; int logfs_readpage(struct file *file, struct page *page); long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync); +int logfs_fsync(struct file *file, int datasync); /* gc.c */ u32 get_best_cand(struct super_block *sb, struct candidate_list *list, u32 *ec); diff --git a/trunk/fs/minix/inode.c b/trunk/fs/minix/inode.c index e7d23e25bf1d..adcdc0a4e182 100644 --- a/trunk/fs/minix/inode.c +++ b/trunk/fs/minix/inode.c @@ -596,7 +596,8 @@ static int minix_write_inode(struct inode *inode, struct writeback_control *wbc) int minix_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct super_block *sb = dentry->d_sb; + struct inode *dir = dentry->d_parent->d_inode; + struct super_block *sb = dir->i_sb; generic_fillattr(dentry->d_inode, stat); if (INODE_VERSION(dentry->d_inode) == MINIX_V1) stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size, sb); diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index b7fad009bbf6..14ab8d3f2f0c 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -176,12 +176,12 @@ EXPORT_SYMBOL(putname); /* * This does basic POSIX ACL permission checking */ -static int acl_permission_check(struct inode *inode, int mask) +static int acl_permission_check(struct inode *inode, int mask, unsigned int flags, + int (*check_acl)(struct inode *inode, int mask, unsigned int flags)) { - int (*check_acl)(struct inode *inode, int mask); unsigned int mode = inode->i_mode; - mask &= MAY_READ | MAY_WRITE | MAY_EXEC | MAY_NOT_BLOCK; + mask &= MAY_READ | MAY_WRITE | MAY_EXEC; if (current_user_ns() != inode_userns(inode)) goto other_perms; @@ -189,9 +189,8 @@ static int acl_permission_check(struct inode *inode, int mask) if (current_fsuid() == inode->i_uid) mode >>= 6; else { - check_acl = inode->i_op->check_acl; if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { - int error = check_acl(inode, mask); + int error = check_acl(inode, mask, flags); if (error != -EAGAIN) return error; } @@ -204,7 +203,7 @@ static int acl_permission_check(struct inode *inode, int mask) /* * If the DACs are ok we don't need any capability check. */ - if ((mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) + if ((mask & ~mode) == 0) return 0; return -EACCES; } @@ -213,6 +212,8 @@ static int acl_permission_check(struct inode *inode, int mask) * generic_permission - check for access rights on a Posix-like filesystem * @inode: inode to check access rights for * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) + * @check_acl: optional callback to check for Posix ACLs + * @flags: IPERM_FLAG_ flags. * * Used to check for read/write/execute permissions on a file. * We use "fsuid" for this, letting us set arbitrary permissions @@ -223,32 +224,24 @@ static int acl_permission_check(struct inode *inode, int mask) * request cannot be satisfied (eg. requires blocking or too much complexity). * It would then be called again in ref-walk mode. */ -int generic_permission(struct inode *inode, int mask) +int generic_permission(struct inode *inode, int mask, unsigned int flags, + int (*check_acl)(struct inode *inode, int mask, unsigned int flags)) { int ret; /* * Do the basic POSIX ACL permission checks. */ - ret = acl_permission_check(inode, mask); + ret = acl_permission_check(inode, mask, flags, check_acl); if (ret != -EACCES) return ret; - if (S_ISDIR(inode->i_mode)) { - /* DACs are overridable for directories */ - if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) - return 0; - if (!(mask & MAY_WRITE)) - if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) - return 0; - return -EACCES; - } /* * Read/write DACs are always overridable. - * Executable DACs are overridable when there is - * at least one exec bit set. + * Executable DACs are overridable for all directories and + * for non-directories that have least one exec bit set. */ - if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) + if (!(mask & MAY_EXEC) || execute_ok(inode)) if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) return 0; @@ -256,7 +249,7 @@ int generic_permission(struct inode *inode, int mask) * Searching includes executable on directories, else just read. */ mask &= MAY_READ | MAY_WRITE | MAY_EXEC; - if (mask == MAY_READ) + if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE))) if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) return 0; @@ -295,9 +288,10 @@ int inode_permission(struct inode *inode, int mask) } if (inode->i_op->permission) - retval = inode->i_op->permission(inode, mask); + retval = inode->i_op->permission(inode, mask, 0); else - retval = generic_permission(inode, mask); + retval = generic_permission(inode, mask, 0, + inode->i_op->check_acl); if (retval) return retval; @@ -309,6 +303,69 @@ int inode_permission(struct inode *inode, int mask) return security_inode_permission(inode, mask); } +/** + * file_permission - check for additional access rights to a given file + * @file: file to check access rights for + * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) + * + * Used to check for read/write/execute permissions on an already opened + * file. + * + * Note: + * Do not use this function in new code. All access checks should + * be done using inode_permission(). + */ +int file_permission(struct file *file, int mask) +{ + return inode_permission(file->f_path.dentry->d_inode, mask); +} + +/* + * get_write_access() gets write permission for a file. + * put_write_access() releases this write permission. + * This is used for regular files. + * We cannot support write (and maybe mmap read-write shared) accesses and + * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode + * can have the following values: + * 0: no writers, no VM_DENYWRITE mappings + * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist + * > 0: (i_writecount) users are writing to the file. + * + * Normally we operate on that counter with atomic_{inc,dec} and it's safe + * except for the cases where we don't hold i_writecount yet. Then we need to + * use {get,deny}_write_access() - these functions check the sign and refuse + * to do the change if sign is wrong. Exclusion between them is provided by + * the inode->i_lock spinlock. + */ + +int get_write_access(struct inode * inode) +{ + spin_lock(&inode->i_lock); + if (atomic_read(&inode->i_writecount) < 0) { + spin_unlock(&inode->i_lock); + return -ETXTBSY; + } + atomic_inc(&inode->i_writecount); + spin_unlock(&inode->i_lock); + + return 0; +} + +int deny_write_access(struct file * file) +{ + struct inode *inode = file->f_path.dentry->d_inode; + + spin_lock(&inode->i_lock); + if (atomic_read(&inode->i_writecount) > 0) { + spin_unlock(&inode->i_lock); + return -ETXTBSY; + } + atomic_dec(&inode->i_writecount); + spin_unlock(&inode->i_lock); + + return 0; +} + /** * path_get - get a reference to a path * @path: path to get the reference to @@ -435,6 +492,28 @@ static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd) return dentry->d_op->d_revalidate(dentry, nd); } +static struct dentry * +do_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + int status = d_revalidate(dentry, nd); + if (unlikely(status <= 0)) { + /* + * The dentry failed validation. + * If d_revalidate returned 0 attempt to invalidate + * the dentry otherwise d_revalidate is asking us + * to return a fail status. + */ + if (status < 0) { + dput(dentry); + dentry = ERR_PTR(status); + } else if (!d_invalidate(dentry)) { + dput(dentry); + dentry = NULL; + } + } + return dentry; +} + /** * complete_walk - successful completion of path walk * @nd: pointer nameidata @@ -489,6 +568,40 @@ static int complete_walk(struct nameidata *nd) return status; } +/* + * Short-cut version of permission(), for calling on directories + * during pathname resolution. Combines parts of permission() + * and generic_permission(), and tests ONLY for MAY_EXEC permission. + * + * If appropriate, check DAC only. If not appropriate, or + * short-cut DAC fails, then call ->permission() to do more + * complete permission check. + */ +static inline int exec_permission(struct inode *inode, unsigned int flags) +{ + int ret; + struct user_namespace *ns = inode_userns(inode); + + if (inode->i_op->permission) { + ret = inode->i_op->permission(inode, MAY_EXEC, flags); + } else { + ret = acl_permission_check(inode, MAY_EXEC, flags, + inode->i_op->check_acl); + } + if (likely(!ret)) + goto ok; + if (ret == -ECHILD) + return ret; + + if (ns_capable(ns, CAP_DAC_OVERRIDE) || + ns_capable(ns, CAP_DAC_READ_SEARCH)) + goto ok; + + return ret; +ok: + return security_inode_exec_permission(inode, flags); +} + static __always_inline void set_root(struct nameidata *nd) { if (!nd->root.mnt) @@ -663,7 +776,7 @@ static int follow_automount(struct path *path, unsigned flags, /* We don't want to mount if someone supplied AT_NO_AUTOMOUNT * and this is the terminal part of the path. */ - if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_PARENT)) + if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE)) return -EISDIR; /* we actually want to stop here */ /* We want to mount if someone is trying to open/create a file of any @@ -675,7 +788,7 @@ static int follow_automount(struct path *path, unsigned flags, * appended a '/' to the name. */ if (!(flags & LOOKUP_FOLLOW) && - !(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | + !(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY | LOOKUP_OPEN | LOOKUP_CREATE))) return -EISDIR; @@ -694,7 +807,7 @@ static int follow_automount(struct path *path, unsigned flags, * the path being looked up; if it wasn't then the remainder of * the path is inaccessible and we should say so. */ - if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_PARENT)) + if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_CONTINUE)) return -EREMOTE; return PTR_ERR(mnt); } @@ -1020,30 +1133,6 @@ static struct dentry *d_alloc_and_lookup(struct dentry *parent, return dentry; } -/* - * We already have a dentry, but require a lookup to be performed on the parent - * directory to fill in d_inode. Returns the new dentry, or ERR_PTR on error. - * parent->d_inode->i_mutex must be held. d_lookup must have verified that no - * child exists while under i_mutex. - */ -static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentry, - struct nameidata *nd) -{ - struct inode *inode = parent->d_inode; - struct dentry *old; - - /* Don't create child dentry for a dead directory. */ - if (unlikely(IS_DEADDIR(inode))) - return ERR_PTR(-ENOENT); - - old = inode->i_op->lookup(inode, dentry, nd); - if (unlikely(old)) { - dput(dentry); - dentry = old; - } - return dentry; -} - /* * It's more convoluted than I'd like it to be, but... it's still fairly * small and for now I'd prefer to have fast path as straight as possible. @@ -1083,8 +1172,6 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, goto unlazy; } } - if (unlikely(d_need_lookup(dentry))) - goto unlazy; path->mnt = mnt; path->dentry = dentry; if (unlikely(!__follow_mount_rcu(nd, path, inode))) @@ -1099,10 +1186,6 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, dentry = __d_lookup(parent, name); } - if (dentry && unlikely(d_need_lookup(dentry))) { - dput(dentry); - dentry = NULL; - } retry: if (unlikely(!dentry)) { struct inode *dir = parent->d_inode; @@ -1119,15 +1202,6 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, /* known good */ need_reval = 0; status = 1; - } else if (unlikely(d_need_lookup(dentry))) { - dentry = d_inode_lookup(parent, dentry, nd); - if (IS_ERR(dentry)) { - mutex_unlock(&dir->i_mutex); - return PTR_ERR(dentry); - } - /* known good */ - need_reval = 0; - status = 1; } mutex_unlock(&dir->i_mutex); } @@ -1160,13 +1234,13 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, static inline int may_lookup(struct nameidata *nd) { if (nd->flags & LOOKUP_RCU) { - int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK); + int err = exec_permission(nd->inode, IPERM_FLAG_RCU); if (err != -ECHILD) return err; if (unlazy_walk(nd, NULL)) return -ECHILD; } - return inode_permission(nd->inode, MAY_EXEC); + return exec_permission(nd->inode, 0); } static inline int handle_dots(struct nameidata *nd, int type) @@ -1280,6 +1354,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) { struct path next; int err; + unsigned int lookup_flags = nd->flags; while (*name=='/') name++; @@ -1293,6 +1368,8 @@ static int link_path_walk(const char *name, struct nameidata *nd) unsigned int c; int type; + nd->flags |= LOOKUP_CONTINUE; + err = may_lookup(nd); if (err) break; @@ -1354,6 +1431,8 @@ static int link_path_walk(const char *name, struct nameidata *nd) /* here ends the main loop */ last_component: + /* Clear LOOKUP_CONTINUE iff it was previously unset */ + nd->flags &= lookup_flags | ~LOOKUP_CONTINUE; nd->last = this; nd->last_type = type; return 0; @@ -1436,7 +1515,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, if (!S_ISDIR(dentry->d_inode->i_mode)) goto fput_fail; - retval = inode_permission(dentry->d_inode, MAY_EXEC); + retval = file_permission(file, MAY_EXEC); if (retval) goto fput_fail; } @@ -1574,22 +1653,16 @@ int kern_path(const char *name, unsigned int flags, struct path *path) * @mnt: pointer to vfs mount of the base directory * @name: pointer to file name * @flags: lookup flags - * @path: pointer to struct path to fill + * @nd: pointer to nameidata */ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, const char *name, unsigned int flags, - struct path *path) + struct nameidata *nd) { - struct nameidata nd; - int err; - nd.root.dentry = dentry; - nd.root.mnt = mnt; - BUG_ON(flags & LOOKUP_PARENT); + nd->root.dentry = dentry; + nd->root.mnt = mnt; /* the first argument of do_path_lookup() is ignored with LOOKUP_ROOT */ - err = do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, &nd); - if (!err) - *path = nd.path; - return err; + return do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, nd); } static struct dentry *__lookup_hash(struct qstr *name, @@ -1599,7 +1672,7 @@ static struct dentry *__lookup_hash(struct qstr *name, struct dentry *dentry; int err; - err = inode_permission(inode, MAY_EXEC); + err = exec_permission(inode, 0); if (err) return ERR_PTR(err); @@ -1610,34 +1683,8 @@ static struct dentry *__lookup_hash(struct qstr *name, */ dentry = d_lookup(base, name); - if (dentry && d_need_lookup(dentry)) { - /* - * __lookup_hash is called with the parent dir's i_mutex already - * held, so we are good to go here. - */ - dentry = d_inode_lookup(base, dentry, nd); - if (IS_ERR(dentry)) - return dentry; - } - - if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) { - int status = d_revalidate(dentry, nd); - if (unlikely(status <= 0)) { - /* - * The dentry failed validation. - * If d_revalidate returned 0 attempt to invalidate - * the dentry otherwise d_revalidate is asking us - * to return a fail status. - */ - if (status < 0) { - dput(dentry); - return ERR_PTR(status); - } else if (!d_invalidate(dentry)) { - dput(dentry); - dentry = NULL; - } - } - } + if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) + dentry = do_revalidate(dentry, nd); if (!dentry) dentry = d_alloc_and_lookup(base, name, nd); @@ -1965,10 +2012,27 @@ static int handle_truncate(struct file *filp) return error; } +/* + * Note that while the flag value (low two bits) for sys_open means: + * 00 - read-only + * 01 - write-only + * 10 - read-write + * 11 - special + * it is changed into + * 00 - no permissions needed + * 01 - read-permission + * 10 - write-permission + * 11 - read-write + * for the internal routines (ie open_namei()/follow_link() etc) + * This is more logical, and also allows the 00 "no perm needed" + * to be used for symlinks (where the permissions are checked + * later). + * +*/ static inline int open_to_namei_flags(int flag) { - if ((flag & O_ACCMODE) == 3) - flag--; + if ((flag+1) & O_ACCMODE) + flag++; return flag; } @@ -2263,29 +2327,35 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, return file; } -struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir) +/** + * lookup_create - lookup a dentry, creating it if it doesn't exist + * @nd: nameidata info + * @is_dir: directory flag + * + * Simple function to lookup and return a dentry and create it + * if it doesn't exist. Is SMP-safe. + * + * Returns with nd->path.dentry->d_inode->i_mutex locked. + */ +struct dentry *lookup_create(struct nameidata *nd, int is_dir) { struct dentry *dentry = ERR_PTR(-EEXIST); - struct nameidata nd; - int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd); - if (error) - return ERR_PTR(error); + mutex_lock_nested(&nd->path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); /* * Yucky last component or no last component at all? * (foo/., foo/.., /////) */ - if (nd.last_type != LAST_NORM) - goto out; - nd.flags &= ~LOOKUP_PARENT; - nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL; - nd.intent.open.flags = O_EXCL; + if (nd->last_type != LAST_NORM) + goto fail; + nd->flags &= ~LOOKUP_PARENT; + nd->flags |= LOOKUP_CREATE | LOOKUP_EXCL; + nd->intent.open.flags = O_EXCL; /* * Do the final lookup. */ - mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); - dentry = lookup_hash(&nd); + dentry = lookup_hash(nd); if (IS_ERR(dentry)) goto fail; @@ -2297,35 +2367,18 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path * all is fine. Let's be bastards - you had / on the end, you've * been asking for (non-existent) directory. -ENOENT for you. */ - if (unlikely(!is_dir && nd.last.name[nd.last.len])) { + if (unlikely(!is_dir && nd->last.name[nd->last.len])) { dput(dentry); dentry = ERR_PTR(-ENOENT); - goto fail; } - *path = nd.path; return dentry; eexist: dput(dentry); dentry = ERR_PTR(-EEXIST); fail: - mutex_unlock(&nd.path.dentry->d_inode->i_mutex); -out: - path_put(&nd.path); return dentry; } -EXPORT_SYMBOL(kern_path_create); - -struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir) -{ - char *tmp = getname(pathname); - struct dentry *res; - if (IS_ERR(tmp)) - return ERR_CAST(tmp); - res = kern_path_create(dfd, tmp, path, is_dir); - putname(tmp); - return res; -} -EXPORT_SYMBOL(user_path_create); +EXPORT_SYMBOL_GPL(lookup_create); int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { @@ -2375,46 +2428,54 @@ static int may_mknod(mode_t mode) SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode, unsigned, dev) { - struct dentry *dentry; - struct path path; int error; + char *tmp; + struct dentry *dentry; + struct nameidata nd; if (S_ISDIR(mode)) return -EPERM; - dentry = user_path_create(dfd, filename, &path, 0); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); + error = user_path_parent(dfd, filename, &nd, &tmp); + if (error) + return error; - if (!IS_POSIXACL(path.dentry->d_inode)) + dentry = lookup_create(&nd, 0); + if (IS_ERR(dentry)) { + error = PTR_ERR(dentry); + goto out_unlock; + } + if (!IS_POSIXACL(nd.path.dentry->d_inode)) mode &= ~current_umask(); error = may_mknod(mode); if (error) goto out_dput; - error = mnt_want_write(path.mnt); + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = security_path_mknod(&path, dentry, mode, dev); + error = security_path_mknod(&nd.path, dentry, mode, dev); if (error) goto out_drop_write; switch (mode & S_IFMT) { case 0: case S_IFREG: - error = vfs_create(path.dentry->d_inode,dentry,mode,NULL); + error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd); break; case S_IFCHR: case S_IFBLK: - error = vfs_mknod(path.dentry->d_inode,dentry,mode, + error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode, new_decode_dev(dev)); break; case S_IFIFO: case S_IFSOCK: - error = vfs_mknod(path.dentry->d_inode,dentry,mode,0); + error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0); break; } out_drop_write: - mnt_drop_write(path.mnt); + mnt_drop_write(nd.path.mnt); out_dput: dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); +out_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); + putname(tmp); return error; } @@ -2447,29 +2508,38 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode) { + int error = 0; + char * tmp; struct dentry *dentry; - struct path path; - int error; + struct nameidata nd; + + error = user_path_parent(dfd, pathname, &nd, &tmp); + if (error) + goto out_err; - dentry = user_path_create(dfd, pathname, &path, 1); + dentry = lookup_create(&nd, 1); + error = PTR_ERR(dentry); if (IS_ERR(dentry)) - return PTR_ERR(dentry); + goto out_unlock; - if (!IS_POSIXACL(path.dentry->d_inode)) + if (!IS_POSIXACL(nd.path.dentry->d_inode)) mode &= ~current_umask(); - error = mnt_want_write(path.mnt); + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = security_path_mkdir(&path, dentry, mode); + error = security_path_mkdir(&nd.path, dentry, mode); if (error) goto out_drop_write; - error = vfs_mkdir(path.dentry->d_inode, dentry, mode); + error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); out_drop_write: - mnt_drop_write(path.mnt); + mnt_drop_write(nd.path.mnt); out_dput: dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); +out_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); + putname(tmp); +out_err: return error; } @@ -2729,31 +2799,38 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, { int error; char *from; + char *to; struct dentry *dentry; - struct path path; + struct nameidata nd; from = getname(oldname); if (IS_ERR(from)) return PTR_ERR(from); - dentry = user_path_create(newdfd, newname, &path, 0); + error = user_path_parent(newdfd, newname, &nd, &to); + if (error) + goto out_putname; + + dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (IS_ERR(dentry)) - goto out_putname; + goto out_unlock; - error = mnt_want_write(path.mnt); + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = security_path_symlink(&path, dentry, from); + error = security_path_symlink(&nd.path, dentry, from); if (error) goto out_drop_write; - error = vfs_symlink(path.dentry->d_inode, dentry, from); + error = vfs_symlink(nd.path.dentry->d_inode, dentry, from); out_drop_write: - mnt_drop_write(path.mnt); + mnt_drop_write(nd.path.mnt); out_dput: dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); +out_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); + putname(to); out_putname: putname(from); return error; @@ -2818,9 +2895,11 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, int, flags) { struct dentry *new_dentry; - struct path old_path, new_path; + struct nameidata nd; + struct path old_path; int how = 0; int error; + char *to; if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) return -EINVAL; @@ -2842,27 +2921,32 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, if (error) return error; - new_dentry = user_path_create(newdfd, newname, &new_path, 0); - error = PTR_ERR(new_dentry); - if (IS_ERR(new_dentry)) + error = user_path_parent(newdfd, newname, &nd, &to); + if (error) goto out; - error = -EXDEV; - if (old_path.mnt != new_path.mnt) - goto out_dput; - error = mnt_want_write(new_path.mnt); + if (old_path.mnt != nd.path.mnt) + goto out_release; + new_dentry = lookup_create(&nd, 0); + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) + goto out_unlock; + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = security_path_link(old_path.dentry, &new_path, new_dentry); + error = security_path_link(old_path.dentry, &nd.path, new_dentry); if (error) goto out_drop_write; - error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); + error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry); out_drop_write: - mnt_drop_write(new_path.mnt); + mnt_drop_write(nd.path.mnt); out_dput: dput(new_dentry); - mutex_unlock(&new_path.dentry->d_inode->i_mutex); - path_put(&new_path); +out_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); +out_release: + path_put(&nd.path); + putname(to); out: path_put(&old_path); @@ -3268,9 +3352,11 @@ EXPORT_SYMBOL(page_readlink); EXPORT_SYMBOL(__page_symlink); EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink_inode_operations); +EXPORT_SYMBOL(kern_path_parent); EXPORT_SYMBOL(kern_path); EXPORT_SYMBOL(vfs_path_lookup); EXPORT_SYMBOL(inode_permission); +EXPORT_SYMBOL(file_permission); EXPORT_SYMBOL(unlock_rename); EXPORT_SYMBOL(vfs_create); EXPORT_SYMBOL(vfs_follow_link); diff --git a/trunk/fs/namespace.c b/trunk/fs/namespace.c index cda50fe9250a..fe59bd145d21 100644 --- a/trunk/fs/namespace.c +++ b/trunk/fs/namespace.c @@ -934,8 +934,8 @@ int mnt_had_events(struct proc_mounts *p) int res = 0; br_read_lock(vfsmount_lock); - if (p->m.poll_event != ns->event) { - p->m.poll_event = ns->event; + if (p->event != ns->event) { + p->event = ns->event; res = 1; } br_read_unlock(vfsmount_lock); diff --git a/trunk/fs/ncpfs/file.c b/trunk/fs/ncpfs/file.c index 64a326418aa2..0ed65e0c3dfe 100644 --- a/trunk/fs/ncpfs/file.c +++ b/trunk/fs/ncpfs/file.c @@ -20,9 +20,9 @@ #include "ncp_fs.h" -static int ncp_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int ncp_fsync(struct file *file, int datasync) { - return filemap_write_and_wait_range(file->f_mapping, start, end); + return 0; } /* diff --git a/trunk/fs/nfs/cache_lib.c b/trunk/fs/nfs/cache_lib.c index c98b439332fc..84690319e625 100644 --- a/trunk/fs/nfs/cache_lib.c +++ b/trunk/fs/nfs/cache_lib.c @@ -113,18 +113,19 @@ int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq) int nfs_cache_register(struct cache_detail *cd) { + struct nameidata nd; struct vfsmount *mnt; - struct path path; int ret; mnt = rpc_get_mount(); if (IS_ERR(mnt)) return PTR_ERR(mnt); - ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &path); + ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &nd); if (ret) goto err; - ret = sunrpc_cache_register_pipefs(path.dentry, cd->name, 0600, cd); - path_put(&path); + ret = sunrpc_cache_register_pipefs(nd.path.dentry, + cd->name, 0600, cd); + path_put(&nd.path); if (!ret) return ret; err: diff --git a/trunk/fs/nfs/dir.c b/trunk/fs/nfs/dir.c index 57f578e2560a..ededdbd0db38 100644 --- a/trunk/fs/nfs/dir.c +++ b/trunk/fs/nfs/dir.c @@ -56,7 +56,7 @@ static int nfs_link(struct dentry *, struct inode *, struct dentry *); static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); -static int nfs_fsync_dir(struct file *, loff_t, loff_t, int); +static int nfs_fsync_dir(struct file *, int); static loff_t nfs_llseek_dir(struct file *, loff_t, int); static void nfs_readdir_clear_array(struct page*); @@ -945,19 +945,15 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) * All directory operations under NFS are synchronous, so fsync() * is a dummy operation. */ -static int nfs_fsync_dir(struct file *filp, loff_t start, loff_t end, - int datasync) +static int nfs_fsync_dir(struct file *filp, int datasync) { struct dentry *dentry = filp->f_path.dentry; - struct inode *inode = dentry->d_inode; dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n", dentry->d_parent->d_name.name, dentry->d_name.name, datasync); - mutex_lock(&inode->i_mutex); nfs_inc_stats(dentry->d_inode, NFSIOS_VFSFSYNC); - mutex_unlock(&inode->i_mutex); return 0; } @@ -1001,12 +997,14 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) * Return the intent data that applies to this particular path component * * Note that the current set of intents only apply to the very last - * component of the path and none of them is set before that last - * component. + * component of the path. + * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT. */ static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask) { + if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT)) + return 0; return nd->flags & mask; } @@ -1340,31 +1338,25 @@ static int is_atomic_open(struct nameidata *nd) return 0; /* Are we trying to write to a read only partition? */ if (__mnt_is_readonly(nd->path.mnt) && - (nd->intent.open.flags & (O_CREAT|O_TRUNC|O_ACCMODE))) + (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE))) return 0; return 1; } -static fmode_t flags_to_mode(int flags) -{ - fmode_t res = (__force fmode_t)flags & FMODE_EXEC; - if ((flags & O_ACCMODE) != O_WRONLY) - res |= FMODE_READ; - if ((flags & O_ACCMODE) != O_RDONLY) - res |= FMODE_WRITE; - return res; -} - -static struct nfs_open_context *create_nfs_open_context(struct dentry *dentry, int open_flags) +static struct nfs_open_context *nameidata_to_nfs_open_context(struct dentry *dentry, struct nameidata *nd) { + struct path path = { + .mnt = nd->path.mnt, + .dentry = dentry, + }; struct nfs_open_context *ctx; struct rpc_cred *cred; - fmode_t fmode = flags_to_mode(open_flags); + fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); cred = rpc_lookup_cred(); if (IS_ERR(cred)) return ERR_CAST(cred); - ctx = alloc_nfs_open_context(dentry, cred, fmode); + ctx = alloc_nfs_open_context(&path, cred, fmode); put_rpccred(cred); if (ctx == NULL) return ERR_PTR(-ENOMEM); @@ -1384,13 +1376,13 @@ static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ct /* If the open_intent is for execute, we have an extra check to make */ if (ctx->mode & FMODE_EXEC) { - ret = nfs_may_open(ctx->dentry->d_inode, + ret = nfs_may_open(ctx->path.dentry->d_inode, ctx->cred, nd->intent.open.flags); if (ret < 0) goto out; } - filp = lookup_instantiate_filp(nd, ctx->dentry, do_open); + filp = lookup_instantiate_filp(nd, ctx->path.dentry, do_open); if (IS_ERR(filp)) ret = PTR_ERR(filp); else @@ -1428,13 +1420,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry goto out; } - open_flags = nd->intent.open.flags; - - ctx = create_nfs_open_context(dentry, open_flags); + ctx = nameidata_to_nfs_open_context(dentry, nd); res = ERR_CAST(ctx); if (IS_ERR(ctx)) goto out; + open_flags = nd->intent.open.flags; if (nd->flags & LOOKUP_CREATE) { attr.ia_mode = nd->intent.open.create_mode; attr.ia_valid = ATTR_MODE; @@ -1472,8 +1463,8 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry res = d_add_unique(dentry, inode); nfs_unblock_sillyrename(dentry->d_parent); if (res != NULL) { - dput(ctx->dentry); - ctx->dentry = dget(res); + dput(ctx->path.dentry); + ctx->path.dentry = dget(res); dentry = res; } err = nfs_intent_set_file(nd, ctx); @@ -1526,7 +1517,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) /* We can't create new files, or truncate existing ones here */ openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); - ctx = create_nfs_open_context(dentry, openflags); + ctx = nameidata_to_nfs_open_context(dentry, nd); ret = PTR_ERR(ctx); if (IS_ERR(ctx)) goto out; @@ -1579,7 +1570,7 @@ static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, struct nfs_open_context *ctx = NULL; struct iattr attr; int error; - int open_flags = O_CREAT|O_EXCL; + int open_flags = 0; dfprintk(VFS, "NFS: create(%s/%ld), %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); @@ -1587,27 +1578,27 @@ static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; - if (nd) + if ((nd->flags & LOOKUP_CREATE) != 0) { open_flags = nd->intent.open.flags; - ctx = create_nfs_open_context(dentry, open_flags); - error = PTR_ERR(ctx); - if (IS_ERR(ctx)) - goto out_err_drop; + ctx = nameidata_to_nfs_open_context(dentry, nd); + error = PTR_ERR(ctx); + if (IS_ERR(ctx)) + goto out_err_drop; + } error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx); if (error != 0) goto out_put_ctx; - if (nd) { + if (ctx != NULL) { error = nfs_intent_set_file(nd, ctx); if (error < 0) goto out_err; - } else { - put_nfs_open_context(ctx); } return 0; out_put_ctx: - put_nfs_open_context(ctx); + if (ctx != NULL) + put_nfs_open_context(ctx); out_err_drop: d_drop(dentry); out_err: @@ -1669,7 +1660,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, { struct iattr attr; int error; - int open_flags = O_CREAT|O_EXCL; + int open_flags = 0; dfprintk(VFS, "NFS: create(%s/%ld), %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); @@ -1677,7 +1668,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; - if (nd) + if ((nd->flags & LOOKUP_CREATE) != 0) open_flags = nd->intent.open.flags; error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, NULL); @@ -2268,11 +2259,11 @@ static int nfs_open_permission_mask(int openflags) { int mask = 0; - if ((openflags & O_ACCMODE) != O_WRONLY) + if (openflags & FMODE_READ) mask |= MAY_READ; - if ((openflags & O_ACCMODE) != O_RDONLY) + if (openflags & FMODE_WRITE) mask |= MAY_WRITE; - if (openflags & __FMODE_EXEC) + if (openflags & FMODE_EXEC) mask |= MAY_EXEC; return mask; } @@ -2282,12 +2273,12 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags) return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags)); } -int nfs_permission(struct inode *inode, int mask) +int nfs_permission(struct inode *inode, int mask, unsigned int flags) { struct rpc_cred *cred; int res = 0; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; nfs_inc_stats(inode, NFSIOS_VFSACCESS); @@ -2337,7 +2328,7 @@ int nfs_permission(struct inode *inode, int mask) out_notsup: res = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (res == 0) - res = generic_permission(inode, mask); + res = generic_permission(inode, mask, flags, NULL); goto out; } diff --git a/trunk/fs/nfs/direct.c b/trunk/fs/nfs/direct.c index b35d25b98da6..8eea25366717 100644 --- a/trunk/fs/nfs/direct.c +++ b/trunk/fs/nfs/direct.c @@ -284,7 +284,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, loff_t pos) { struct nfs_open_context *ctx = dreq->ctx; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; unsigned long user_addr = (unsigned long)iov->iov_base; size_t count = iov->iov_len; size_t rsize = NFS_SERVER(inode)->rsize; @@ -715,7 +715,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, loff_t pos, int sync) { struct nfs_open_context *ctx = dreq->ctx; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; unsigned long user_addr = (unsigned long)iov->iov_base; size_t count = iov->iov_len; struct rpc_task *task; diff --git a/trunk/fs/nfs/file.c b/trunk/fs/nfs/file.c index 28b8c3f3cda3..2f093ed16980 100644 --- a/trunk/fs/nfs/file.c +++ b/trunk/fs/nfs/file.c @@ -55,7 +55,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, unsigned long nr_segs, loff_t pos); static int nfs_file_flush(struct file *, fl_owner_t id); -static int nfs_file_fsync(struct file *, loff_t, loff_t, int datasync); +static int nfs_file_fsync(struct file *, int datasync); static int nfs_check_flags(int flags); static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); @@ -187,11 +187,8 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) filp->f_path.dentry->d_name.name, offset, origin); - /* - * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate - * the cached file length - */ - if (origin != SEEK_SET || origin != SEEK_CUR) { + /* origin == SEEK_END => we must revalidate the cached file length */ + if (origin == SEEK_END) { struct inode *inode = filp->f_mapping->host; int retval = nfs_revalidate_file_size(inode, filp); @@ -308,7 +305,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) * fall back to doing a synchronous write. */ static int -nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) +nfs_file_fsync(struct file *file, int datasync) { struct dentry *dentry = file->f_path.dentry; struct nfs_open_context *ctx = nfs_file_open_context(file); @@ -316,15 +313,11 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) int have_error, status; int ret = 0; + dprintk("NFS: fsync file(%s/%s) datasync %d\n", dentry->d_parent->d_name.name, dentry->d_name.name, datasync); - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - mutex_lock(&inode->i_mutex); - nfs_inc_stats(inode, NFSIOS_VFSFSYNC); have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); status = nfs_commit_inode(inode, FLUSH_SYNC); @@ -336,7 +329,6 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) if (!ret && !datasync) /* application has asked for meta-data sync */ ret = pnfs_layoutcommit_inode(inode, true); - mutex_unlock(&inode->i_mutex); return ret; } diff --git a/trunk/fs/nfs/inode.c b/trunk/fs/nfs/inode.c index fe1203797b2b..6f4850deb272 100644 --- a/trunk/fs/nfs/inode.c +++ b/trunk/fs/nfs/inode.c @@ -567,7 +567,7 @@ static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) { struct nfs_lock_context *res, *new = NULL; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; spin_lock(&inode->i_lock); res = __nfs_find_lock_context(ctx); @@ -594,7 +594,7 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) void nfs_put_lock_context(struct nfs_lock_context *l_ctx) { struct nfs_open_context *ctx = l_ctx->open_context; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock)) return; @@ -620,7 +620,7 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) return; if (!is_sync) return; - inode = ctx->dentry->d_inode; + inode = ctx->path.dentry->d_inode; if (!list_empty(&NFS_I(inode)->open_files)) return; server = NFS_SERVER(inode); @@ -629,14 +629,14 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) nfs_revalidate_inode(server, inode); } -struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred, fmode_t f_mode) +struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode) { struct nfs_open_context *ctx; ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (ctx != NULL) { - nfs_sb_active(dentry->d_sb); - ctx->dentry = dget(dentry); + ctx->path = *path; + path_get(&ctx->path); ctx->cred = get_rpccred(cred); ctx->state = NULL; ctx->mode = f_mode; @@ -658,8 +658,7 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) { - struct inode *inode = ctx->dentry->d_inode; - struct super_block *sb = ctx->dentry->d_sb; + struct inode *inode = ctx->path.dentry->d_inode; if (!list_empty(&ctx->list)) { if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock)) @@ -672,8 +671,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) NFS_PROTO(inode)->close_context(ctx, is_sync); if (ctx->cred != NULL) put_rpccred(ctx->cred); - dput(ctx->dentry); - nfs_sb_deactive(sb); + path_put(&ctx->path); kfree(ctx); } @@ -743,7 +741,7 @@ int nfs_open(struct inode *inode, struct file *filp) cred = rpc_lookup_cred(); if (IS_ERR(cred)) return PTR_ERR(cred); - ctx = alloc_nfs_open_context(filp->f_path.dentry, cred, filp->f_mode); + ctx = alloc_nfs_open_context(&filp->f_path, cred, filp->f_mode); put_rpccred(cred); if (ctx == NULL) return -ENOMEM; diff --git a/trunk/fs/nfs/nfs4_fs.h b/trunk/fs/nfs/nfs4_fs.h index b788f2eb1ba0..c4a69833dd0d 100644 --- a/trunk/fs/nfs/nfs4_fs.h +++ b/trunk/fs/nfs/nfs4_fs.h @@ -238,7 +238,7 @@ extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); -extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); +extern int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, struct nfs4_fs_locations *fs_locations, struct page *page); @@ -341,8 +341,8 @@ extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struc extern void nfs4_put_state_owner(struct nfs4_state_owner *); extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); extern void nfs4_put_open_state(struct nfs4_state *); -extern void nfs4_close_state(struct nfs4_state *, fmode_t); -extern void nfs4_close_sync(struct nfs4_state *, fmode_t); +extern void nfs4_close_state(struct path *, struct nfs4_state *, fmode_t); +extern void nfs4_close_sync(struct path *, struct nfs4_state *, fmode_t); extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); extern void nfs4_schedule_lease_recovery(struct nfs_client *); extern void nfs4_schedule_state_manager(struct nfs_client *); @@ -373,8 +373,8 @@ extern struct svc_version nfs4_callback_version4; #else -#define nfs4_close_state(a, b) do { } while (0) -#define nfs4_close_sync(a, b) do { } while (0) +#define nfs4_close_state(a, b, c) do { } while (0) +#define nfs4_close_sync(a, b, c) do { } while (0) #endif /* CONFIG_NFS_V4 */ #endif /* __LINUX_FS_NFS_NFS4_FS.H */ diff --git a/trunk/fs/nfs/nfs4proc.c b/trunk/fs/nfs/nfs4proc.c index 26bece8f3083..5879b23e0c99 100644 --- a/trunk/fs/nfs/nfs4proc.c +++ b/trunk/fs/nfs/nfs4proc.c @@ -763,8 +763,8 @@ struct nfs4_opendata { struct nfs_open_confirmres c_res; struct nfs_fattr f_attr; struct nfs_fattr dir_attr; + struct path path; struct dentry *dir; - struct dentry *dentry; struct nfs4_state_owner *owner; struct nfs4_state *state; struct iattr attrs; @@ -786,12 +786,12 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) nfs_fattr_init(&p->dir_attr); } -static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, +static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, struct nfs4_state_owner *sp, fmode_t fmode, int flags, const struct iattr *attrs, gfp_t gfp_mask) { - struct dentry *parent = dget_parent(dentry); + struct dentry *parent = dget_parent(path->dentry); struct inode *dir = parent->d_inode; struct nfs_server *server = NFS_SERVER(dir); struct nfs4_opendata *p; @@ -802,8 +802,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask); if (p->o_arg.seqid == NULL) goto err_free; - nfs_sb_active(dentry->d_sb); - p->dentry = dget(dentry); + path_get(path); + p->path = *path; p->dir = parent; p->owner = sp; atomic_inc(&sp->so_count); @@ -812,7 +812,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); p->o_arg.clientid = server->nfs_client->cl_clientid; p->o_arg.id = sp->so_owner_id.id; - p->o_arg.name = &dentry->d_name; + p->o_arg.name = &p->path.dentry->d_name; p->o_arg.server = server; p->o_arg.bitmask = server->attr_bitmask; p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; @@ -842,15 +842,13 @@ static void nfs4_opendata_free(struct kref *kref) { struct nfs4_opendata *p = container_of(kref, struct nfs4_opendata, kref); - struct super_block *sb = p->dentry->d_sb; nfs_free_seqid(p->o_arg.seqid); if (p->state != NULL) nfs4_put_open_state(p->state); nfs4_put_state_owner(p->owner); dput(p->dir); - dput(p->dentry); - nfs_sb_deactive(sb); + path_put(&p->path); kfree(p); } @@ -1132,7 +1130,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context { struct nfs4_opendata *opendata; - opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, GFP_NOFS); + opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL, GFP_NOFS); if (opendata == NULL) return ERR_PTR(-ENOMEM); opendata->state = state; @@ -1156,7 +1154,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod newstate = nfs4_opendata_to_nfs4_state(opendata); if (IS_ERR(newstate)) return PTR_ERR(newstate); - nfs4_close_state(newstate, fmode); + nfs4_close_state(&opendata->path, newstate, fmode); *res = newstate; return 0; } @@ -1354,7 +1352,7 @@ static void nfs4_open_confirm_release(void *calldata) goto out_free; state = nfs4_opendata_to_nfs4_state(data); if (!IS_ERR(state)) - nfs4_close_state(state, data->o_arg.fmode); + nfs4_close_state(&data->path, state, data->o_arg.fmode); out_free: nfs4_opendata_put(data); } @@ -1499,7 +1497,7 @@ static void nfs4_open_release(void *calldata) goto out_free; state = nfs4_opendata_to_nfs4_state(data); if (!IS_ERR(state)) - nfs4_close_state(state, data->o_arg.fmode); + nfs4_close_state(&data->path, state, data->o_arg.fmode); out_free: nfs4_opendata_put(data); } @@ -1650,7 +1648,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s return PTR_ERR(opendata); ret = nfs4_open_recover(opendata, state); if (ret == -ESTALE) - d_drop(ctx->dentry); + d_drop(ctx->path.dentry); nfs4_opendata_put(opendata); return ret; } @@ -1708,7 +1706,7 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct /* * Returns a referenced nfs4_state */ -static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) +static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) { struct nfs4_state_owner *sp; struct nfs4_state *state = NULL; @@ -1725,15 +1723,15 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode status = nfs4_recover_expired_lease(server); if (status != 0) goto err_put_state_owner; - if (dentry->d_inode != NULL) - nfs4_return_incompatible_delegation(dentry->d_inode, fmode); + if (path->dentry->d_inode != NULL) + nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); status = -ENOMEM; - opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, GFP_KERNEL); + opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr, GFP_KERNEL); if (opendata == NULL) goto err_put_state_owner; - if (dentry->d_inode != NULL) - opendata->state = nfs4_get_open_state(dentry->d_inode, sp); + if (path->dentry->d_inode != NULL) + opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); status = _nfs4_proc_open(opendata); if (status != 0) @@ -1771,14 +1769,14 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode } -static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred) +static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred) { struct nfs4_exception exception = { }; struct nfs4_state *res; int status; do { - status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred, &res); + status = _nfs4_do_open(dir, path, fmode, flags, sattr, cred, &res); if (status == 0) break; /* NOTE: BAD_SEQID means the server and client disagree about the @@ -1875,6 +1873,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, } struct nfs4_closedata { + struct path path; struct inode *inode; struct nfs4_state *state; struct nfs_closeargs arg; @@ -1889,14 +1888,13 @@ static void nfs4_free_closedata(void *data) { struct nfs4_closedata *calldata = data; struct nfs4_state_owner *sp = calldata->state->owner; - struct super_block *sb = calldata->state->inode->i_sb; if (calldata->roc) pnfs_roc_release(calldata->state->inode); nfs4_put_open_state(calldata->state); nfs_free_seqid(calldata->arg.seqid); nfs4_put_state_owner(sp); - nfs_sb_deactive(sb); + path_put(&calldata->path); kfree(calldata); } @@ -2016,7 +2014,7 @@ static const struct rpc_call_ops nfs4_close_ops = { * * NOTE: Caller must be holding the sp->so_owner semaphore! */ -int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc) +int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc) { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs4_closedata *calldata; @@ -2052,7 +2050,8 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc) calldata->res.seqid = calldata->arg.seqid; calldata->res.server = server; calldata->roc = roc; - nfs_sb_active(calldata->inode->i_sb); + path_get(path); + calldata->path = *path; msg.rpc_argp = &calldata->arg; msg.rpc_resp = &calldata->res; @@ -2081,7 +2080,7 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags struct nfs4_state *state; /* Protect against concurrent sillydeletes */ - state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, ctx->cred); + state = nfs4_do_open(dir, &ctx->path, ctx->mode, open_flags, attr, ctx->cred); if (IS_ERR(state)) return ERR_CAST(state); ctx->state = state; @@ -2093,9 +2092,9 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) if (ctx->state == NULL) return; if (is_sync) - nfs4_close_sync(ctx->state, ctx->mode); + nfs4_close_sync(&ctx->path, ctx->state, ctx->mode); else - nfs4_close_state(ctx->state, ctx->mode); + nfs4_close_state(&ctx->path, ctx->state, ctx->mode); } static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) @@ -2617,7 +2616,10 @@ static int nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags, struct nfs_open_context *ctx) { - struct dentry *de = dentry; + struct path my_path = { + .dentry = dentry, + }; + struct path *path = &my_path; struct nfs4_state *state; struct rpc_cred *cred = NULL; fmode_t fmode = 0; @@ -2625,11 +2627,11 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, if (ctx != NULL) { cred = ctx->cred; - de = ctx->dentry; + path = &ctx->path; fmode = ctx->mode; } sattr->ia_mode &= ~current_umask(); - state = nfs4_do_open(dir, de, fmode, flags, sattr, cred); + state = nfs4_do_open(dir, path, fmode, flags, sattr, cred); d_drop(dentry); if (IS_ERR(state)) { status = PTR_ERR(state); @@ -2640,7 +2642,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, if (ctx != NULL) ctx->state = state; else - nfs4_close_sync(state, fmode); + nfs4_close_sync(path, state, fmode); out: return status; } @@ -4292,7 +4294,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, sizeof(data->lsp->ls_stateid.data)); data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; - renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); + renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); } out: dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status); diff --git a/trunk/fs/nfs/nfs4state.c b/trunk/fs/nfs/nfs4state.c index 7acfe8843626..e97dd219f84f 100644 --- a/trunk/fs/nfs/nfs4state.c +++ b/trunk/fs/nfs/nfs4state.c @@ -641,7 +641,7 @@ void nfs4_put_open_state(struct nfs4_state *state) /* * Close the current file. */ -static void __nfs4_close(struct nfs4_state *state, +static void __nfs4_close(struct path *path, struct nfs4_state *state, fmode_t fmode, gfp_t gfp_mask, int wait) { struct nfs4_state_owner *owner = state->owner; @@ -685,18 +685,18 @@ static void __nfs4_close(struct nfs4_state *state, } else { bool roc = pnfs_roc(state->inode); - nfs4_do_close(state, gfp_mask, wait, roc); + nfs4_do_close(path, state, gfp_mask, wait, roc); } } -void nfs4_close_state(struct nfs4_state *state, fmode_t fmode) +void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode) { - __nfs4_close(state, fmode, GFP_NOFS, 0); + __nfs4_close(path, state, fmode, GFP_NOFS, 0); } -void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode) +void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode) { - __nfs4_close(state, fmode, GFP_KERNEL, 1); + __nfs4_close(path, state, fmode, GFP_KERNEL, 1); } /* diff --git a/trunk/fs/nfs/pagelist.c b/trunk/fs/nfs/pagelist.c index 18449f43c568..009855716286 100644 --- a/trunk/fs/nfs/pagelist.c +++ b/trunk/fs/nfs/pagelist.c @@ -114,7 +114,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) if (!nfs_lock_request_dontget(req)) return 0; if (test_bit(PG_MAPPED, &req->wb_flags)) - radix_tree_tag_set(&NFS_I(req->wb_context->dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); + radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); return 1; } @@ -124,7 +124,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) void nfs_clear_page_tag_locked(struct nfs_page *req) { if (test_bit(PG_MAPPED, &req->wb_flags)) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&inode->i_lock); diff --git a/trunk/fs/nfs/read.c b/trunk/fs/nfs/read.c index a68679f538fc..20a7f952e244 100644 --- a/trunk/fs/nfs/read.c +++ b/trunk/fs/nfs/read.c @@ -144,7 +144,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, static void nfs_readpage_release(struct nfs_page *req) { - struct inode *d_inode = req->wb_context->dentry->d_inode; + struct inode *d_inode = req->wb_context->path.dentry->d_inode; if (PageUptodate(req->wb_page)) nfs_readpage_to_fscache(d_inode, req->wb_page, 0); @@ -152,8 +152,8 @@ static void nfs_readpage_release(struct nfs_page *req) unlock_page(req->wb_page); dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", - req->wb_context->dentry->d_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); nfs_release_request(req); @@ -207,7 +207,7 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, unsigned int count, unsigned int offset, struct pnfs_layout_segment *lseg) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; data->req = req; data->inode = inode; diff --git a/trunk/fs/nfs/super.c b/trunk/fs/nfs/super.c index b961ceac66b4..ce40e5c568ba 100644 --- a/trunk/fs/nfs/super.c +++ b/trunk/fs/nfs/super.c @@ -2773,12 +2773,16 @@ static void nfs_referral_loop_unprotect(void) static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, const char *export_path) { + struct nameidata *nd = NULL; struct mnt_namespace *ns_private; struct super_block *s; struct dentry *dentry; - struct path path; int ret; + nd = kmalloc(sizeof(*nd), GFP_KERNEL); + if (nd == NULL) + return ERR_PTR(-ENOMEM); + ns_private = create_mnt_ns(root_mnt); ret = PTR_ERR(ns_private); if (IS_ERR(ns_private)) @@ -2789,7 +2793,7 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, goto out_put_mnt_ns; ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, - export_path, LOOKUP_FOLLOW, &path); + export_path, LOOKUP_FOLLOW, nd); nfs_referral_loop_unprotect(); put_mnt_ns(ns_private); @@ -2797,11 +2801,12 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, if (ret != 0) goto out_err; - s = path.mnt->mnt_sb; + s = nd->path.mnt->mnt_sb; atomic_inc(&s->s_active); - dentry = dget(path.dentry); + dentry = dget(nd->path.dentry); - path_put(&path); + path_put(&nd->path); + kfree(nd); down_write(&s->s_umount); return dentry; out_put_mnt_ns: @@ -2809,6 +2814,7 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, out_mntput: mntput(root_mnt); out_err: + kfree(nd); return ERR_PTR(ret); } diff --git a/trunk/fs/nfs/write.c b/trunk/fs/nfs/write.c index 08579312c57b..727168059684 100644 --- a/trunk/fs/nfs/write.c +++ b/trunk/fs/nfs/write.c @@ -409,7 +409,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) */ static void nfs_inode_remove_request(struct nfs_page *req) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); BUG_ON (!NFS_WBACK_BUSY(req)); @@ -438,7 +438,7 @@ nfs_mark_request_dirty(struct nfs_page *req) static void nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&inode->i_lock); @@ -852,13 +852,13 @@ static int nfs_write_rpcsetup(struct nfs_page *req, struct pnfs_layout_segment *lseg, int how) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; /* Set up the RPC argument and reply structs * NB: take care not to mess about with data->commit et al. */ data->req = req; - data->inode = inode = req->wb_context->dentry->d_inode; + data->inode = inode = req->wb_context->path.dentry->d_inode; data->cred = req->wb_context->cred; data->lseg = get_lseg(lseg); @@ -1053,9 +1053,9 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) dprintk("NFS: %5u write(%s/%lld %d@%lld)", task->tk_pid, - data->req->wb_context->dentry->d_inode->i_sb->s_id, + data->req->wb_context->path.dentry->d_inode->i_sb->s_id, (long long) - NFS_FILEID(data->req->wb_context->dentry->d_inode), + NFS_FILEID(data->req->wb_context->path.dentry->d_inode), data->req->wb_bytes, (long long)req_offset(data->req)); nfs_writeback_done(task, data); @@ -1148,8 +1148,8 @@ static void nfs_writeback_release_full(void *calldata) dprintk("NFS: %5u write (%s/%lld %d@%lld)", data->task.tk_pid, - req->wb_context->dentry->d_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); @@ -1347,7 +1347,7 @@ void nfs_init_commit(struct nfs_write_data *data, struct pnfs_layout_segment *lseg) { struct nfs_page *first = nfs_list_entry(head->next); - struct inode *inode = first->wb_context->dentry->d_inode; + struct inode *inode = first->wb_context->path.dentry->d_inode; /* Set up the RPC argument and reply structs * NB: take care not to mess about with data->commit et al. */ @@ -1435,8 +1435,8 @@ void nfs_commit_release_pages(struct nfs_write_data *data) nfs_clear_request_commit(req); dprintk("NFS: commit (%s/%lld %d@%lld)", - req->wb_context->dentry->d_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); if (status < 0) { diff --git a/trunk/fs/nfsd/nfs4recover.c b/trunk/fs/nfsd/nfs4recover.c index 29d77f60585b..ffb59ef6f82f 100644 --- a/trunk/fs/nfsd/nfs4recover.c +++ b/trunk/fs/nfsd/nfs4recover.c @@ -191,42 +191,52 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen, } static int -nfsd4_list_rec_dir(recdir_func *f) +nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) { const struct cred *original_cred; - struct dentry *dir = rec_file->f_path.dentry; + struct file *filp; LIST_HEAD(names); + struct name_list *entry; + struct dentry *dentry; int status; + if (!rec_file) + return 0; + status = nfs4_save_creds(&original_cred); if (status < 0) return status; - status = vfs_llseek(rec_file, 0, SEEK_SET); - if (status < 0) { - nfs4_reset_creds(original_cred); - return status; - } - - status = vfs_readdir(rec_file, nfsd4_build_namelist, &names); + filp = dentry_open(dget(dir), mntget(rec_file->f_path.mnt), O_RDONLY, + current_cred()); + status = PTR_ERR(filp); + if (IS_ERR(filp)) + goto out; + status = vfs_readdir(filp, nfsd4_build_namelist, &names); + fput(filp); mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); while (!list_empty(&names)) { - struct name_list *entry; entry = list_entry(names.next, struct name_list, list); - if (!status) { - struct dentry *dentry; - dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); - if (IS_ERR(dentry)) { - status = PTR_ERR(dentry); - break; - } - status = f(dir, dentry); - dput(dentry); + + dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); + if (IS_ERR(dentry)) { + status = PTR_ERR(dentry); + break; } + status = f(dir, dentry); + dput(dentry); + if (status) + break; list_del(&entry->list); kfree(entry); } mutex_unlock(&dir->d_inode->i_mutex); +out: + while (!list_empty(&names)) { + entry = list_entry(names.next, struct name_list, list); + list_del(&entry->list); + kfree(entry); + } nfs4_reset_creds(original_cred); return status; } @@ -312,7 +322,7 @@ nfsd4_recdir_purge_old(void) { status = mnt_want_write(rec_file->f_path.mnt); if (status) goto out; - status = nfsd4_list_rec_dir(purge_old); + status = nfsd4_list_rec_dir(rec_file->f_path.dentry, purge_old); if (status == 0) vfs_fsync(rec_file, 0); mnt_drop_write(rec_file->f_path.mnt); @@ -342,7 +352,7 @@ nfsd4_recdir_load(void) { if (!rec_file) return 0; - status = nfsd4_list_rec_dir(load_recdir); + status = nfsd4_list_rec_dir(rec_file->f_path.dentry, load_recdir); if (status) printk("nfsd4: failed loading clients from recovery" " directory %s\n", rec_file->f_path.dentry->d_name.name); diff --git a/trunk/fs/nilfs2/file.c b/trunk/fs/nilfs2/file.c index 26601529dc17..d7eeca62febd 100644 --- a/trunk/fs/nilfs2/file.c +++ b/trunk/fs/nilfs2/file.c @@ -27,7 +27,7 @@ #include "nilfs.h" #include "segment.h" -int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +int nilfs_sync_file(struct file *file, int datasync) { /* * Called from fsync() system call @@ -40,15 +40,8 @@ int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) struct inode *inode = file->f_mapping->host; int err; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - mutex_lock(&inode->i_mutex); - - if (!nilfs_inode_dirty(inode)) { - mutex_unlock(&inode->i_mutex); + if (!nilfs_inode_dirty(inode)) return 0; - } if (datasync) err = nilfs_construct_dsync_segment(inode->i_sb, inode, 0, @@ -56,7 +49,6 @@ int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) else err = nilfs_construct_segment(inode->i_sb); - mutex_unlock(&inode->i_mutex); return err; } diff --git a/trunk/fs/nilfs2/inode.c b/trunk/fs/nilfs2/inode.c index 666628b395f1..b9b45fc2903e 100644 --- a/trunk/fs/nilfs2/inode.c +++ b/trunk/fs/nilfs2/inode.c @@ -259,8 +259,8 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, return 0; /* Needs synchronization with the cleaner */ - size = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - nilfs_get_block); + size = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, nilfs_get_block, NULL); /* * In case of error extending write may have instantiated a few @@ -778,8 +778,6 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size != i_size_read(inode)) { - inode_dio_wait(inode); - err = vmtruncate(inode, iattr->ia_size); if (unlikely(err)) goto out_err; @@ -801,14 +799,14 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) return err; } -int nilfs_permission(struct inode *inode, int mask) +int nilfs_permission(struct inode *inode, int mask, unsigned int flags) { struct nilfs_root *root = NILFS_I(inode)->i_root; if ((mask & MAY_WRITE) && root && root->cno != NILFS_CPTREE_CURRENT_CNO) return -EROFS; /* snapshot is not writable */ - return generic_permission(inode, mask); + return generic_permission(inode, mask, flags, NULL); } int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh) diff --git a/trunk/fs/nilfs2/namei.c b/trunk/fs/nilfs2/namei.c index a3141990061e..546849b3e88f 100644 --- a/trunk/fs/nilfs2/namei.c +++ b/trunk/fs/nilfs2/namei.c @@ -72,7 +72,12 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) return ERR_PTR(-ENAMETOOLONG); ino = nilfs_inode_by_name(dir, &dentry->d_name); - inode = ino ? nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino) : NULL; + inode = NULL; + if (ino) { + inode = nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + } return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/nilfs2/nilfs.h b/trunk/fs/nilfs2/nilfs.h index 255d5e1c03b7..f02b9ad43a21 100644 --- a/trunk/fs/nilfs2/nilfs.h +++ b/trunk/fs/nilfs2/nilfs.h @@ -235,7 +235,7 @@ extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *, struct page *, struct inode *); /* file.c */ -extern int nilfs_sync_file(struct file *, loff_t, loff_t, int); +extern int nilfs_sync_file(struct file *, int); /* ioctl.c */ long nilfs_ioctl(struct file *, unsigned int, unsigned long); @@ -264,7 +264,7 @@ extern void nilfs_update_inode(struct inode *, struct buffer_head *); extern void nilfs_truncate(struct inode *); extern void nilfs_evict_inode(struct inode *); extern int nilfs_setattr(struct dentry *, struct iattr *); -int nilfs_permission(struct inode *inode, int mask); +int nilfs_permission(struct inode *inode, int mask, unsigned int flags); int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh); extern int nilfs_inode_dirty(struct inode *); int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty); diff --git a/trunk/fs/ntfs/dir.c b/trunk/fs/ntfs/dir.c index 99e36107ff60..0f48e7c5d9e1 100644 --- a/trunk/fs/ntfs/dir.c +++ b/trunk/fs/ntfs/dir.c @@ -1527,20 +1527,13 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp) * this problem for now. We do write the $BITMAP attribute if it is present * which is the important one for a directory so things are not too bad. */ -static int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int ntfs_dir_fsync(struct file *filp, int datasync) { struct inode *bmp_vi, *vi = filp->f_mapping->host; int err, ret; ntfs_attr na; ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); - - err = filemap_write_and_wait_range(vi->i_mapping, start, end); - if (err) - return err; - mutex_lock(&vi->i_mutex); - BUG_ON(!S_ISDIR(vi->i_mode)); /* If the bitmap attribute inode is in memory sync it, too. */ na.mft_no = vi->i_ino; @@ -1562,7 +1555,6 @@ static int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end, else ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " "%u.", datasync ? "data" : "", vi->i_ino, -ret); - mutex_unlock(&vi->i_mutex); return ret; } diff --git a/trunk/fs/ntfs/file.c b/trunk/fs/ntfs/file.c index c587e2d27183..f4b1057abdd2 100644 --- a/trunk/fs/ntfs/file.c +++ b/trunk/fs/ntfs/file.c @@ -1832,8 +1832,9 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, * fails again. */ if (unlikely(NInoTruncateFailed(ni))) { - inode_dio_wait(vi); + down_write(&vi->i_alloc_sem); err = ntfs_truncate(vi); + up_write(&vi->i_alloc_sem); if (err || NInoTruncateFailed(ni)) { if (!err) err = -EIO; @@ -2152,19 +2153,12 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, * with this inode but since we have no simple way of getting to them we ignore * this problem for now. */ -static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int ntfs_file_fsync(struct file *filp, int datasync) { struct inode *vi = filp->f_mapping->host; int err, ret = 0; ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); - - err = filemap_write_and_wait_range(vi->i_mapping, start, end); - if (err) - return err; - mutex_lock(&vi->i_mutex); - BUG_ON(S_ISDIR(vi->i_mode)); if (!datasync || !NInoNonResident(NTFS_I(vi))) ret = __ntfs_write_inode(vi, 1); @@ -2182,7 +2176,6 @@ static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end, else ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " "%u.", datasync ? "data" : "", vi->i_ino, -ret); - mutex_unlock(&vi->i_mutex); return ret; } diff --git a/trunk/fs/ntfs/inode.c b/trunk/fs/ntfs/inode.c index 1371487da955..c05d6dcf77a4 100644 --- a/trunk/fs/ntfs/inode.c +++ b/trunk/fs/ntfs/inode.c @@ -2357,7 +2357,12 @@ static const char *es = " Leaving inconsistent metadata. Unmount and run " * * Returns 0 on success or -errno on error. * - * Called with ->i_mutex held. + * Called with ->i_mutex held. In all but one case ->i_alloc_sem is held for + * writing. The only case in the kernel where ->i_alloc_sem is not held is + * mm/filemap.c::generic_file_buffered_write() where vmtruncate() is called + * with the current i_size as the offset. The analogous place in NTFS is in + * fs/ntfs/file.c::ntfs_file_buffered_write() where we call vmtruncate() again + * without holding ->i_alloc_sem. */ int ntfs_truncate(struct inode *vi) { @@ -2882,7 +2887,8 @@ void ntfs_truncate_vfs(struct inode *vi) { * We also abort all changes of user, group, and mode as we do not implement * the NTFS ACLs yet. * - * Called with ->i_mutex held. + * Called with ->i_mutex held. For the ATTR_SIZE (i.e. ->truncate) case, also + * called with ->i_alloc_sem held for writing. */ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) { diff --git a/trunk/fs/ocfs2/acl.c b/trunk/fs/ocfs2/acl.c index 1cee970eb55a..e913ad130fdd 100644 --- a/trunk/fs/ocfs2/acl.c +++ b/trunk/fs/ocfs2/acl.c @@ -290,14 +290,14 @@ static int ocfs2_set_acl(handle_t *handle, return ret; } -int ocfs2_check_acl(struct inode *inode, int mask) +int ocfs2_check_acl(struct inode *inode, int mask, unsigned int flags) { struct ocfs2_super *osb; struct buffer_head *di_bh = NULL; struct posix_acl *acl; int ret = -EAGAIN; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; osb = OCFS2_SB(inode->i_sb); diff --git a/trunk/fs/ocfs2/acl.h b/trunk/fs/ocfs2/acl.h index 5c5d31f05853..4fe7c9cf4bfb 100644 --- a/trunk/fs/ocfs2/acl.h +++ b/trunk/fs/ocfs2/acl.h @@ -26,7 +26,7 @@ struct ocfs2_acl_entry { __le32 e_id; }; -extern int ocfs2_check_acl(struct inode *, int); +extern int ocfs2_check_acl(struct inode *, int, unsigned int); extern int ocfs2_acl_chmod(struct inode *); extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *, struct buffer_head *, struct buffer_head *, diff --git a/trunk/fs/ocfs2/aops.c b/trunk/fs/ocfs2/aops.c index c1efe939c774..ac97bca282d2 100644 --- a/trunk/fs/ocfs2/aops.c +++ b/trunk/fs/ocfs2/aops.c @@ -551,8 +551,9 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, /* * ocfs2_dio_end_io is called by the dio core when a dio is finished. We're - * particularly interested in the aio/dio case. We use the rw_lock DLM lock - * to protect io on one node from truncation on another. + * particularly interested in the aio/dio case. Like the core uses + * i_alloc_sem, we use the rw_lock DLM lock to protect io on one node from + * truncation on another. */ static void ocfs2_dio_end_io(struct kiocb *iocb, loff_t offset, @@ -567,8 +568,10 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, /* this io's submitter should not have unlocked this before we could */ BUG_ON(!ocfs2_iocb_is_rw_locked(iocb)); - if (ocfs2_iocb_is_sem_locked(iocb)) + if (ocfs2_iocb_is_sem_locked(iocb)) { + up_read(&inode->i_alloc_sem); ocfs2_iocb_clear_sem_locked(iocb); + } ocfs2_iocb_clear_rw_locked(iocb); @@ -577,7 +580,6 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, if (is_async) aio_complete(iocb, ret, 0); - inode_dio_done(inode); } /* diff --git a/trunk/fs/ocfs2/file.c b/trunk/fs/ocfs2/file.c index 0fc2bd34039d..b1e35a392ca5 100644 --- a/trunk/fs/ocfs2/file.c +++ b/trunk/fs/ocfs2/file.c @@ -171,8 +171,7 @@ static int ocfs2_dir_release(struct inode *inode, struct file *file) return 0; } -static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end, - int datasync) +static int ocfs2_sync_file(struct file *file, int datasync) { int err = 0; journal_t *journal; @@ -185,16 +184,6 @@ static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end, file->f_path.dentry->d_name.name, (unsigned long long)datasync); - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - /* - * Probably don't need the i_mutex at all in here, just putting it here - * to be consistent with how fsync used to be called, someone more - * familiar with the fs could possibly remove it. - */ - mutex_lock(&inode->i_mutex); if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) { /* * We still have to flush drive's caches to get data to the @@ -211,7 +200,6 @@ static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end, bail: if (err) mlog_errno(err); - mutex_unlock(&inode->i_mutex); return (err < 0) ? -EIO : 0; } @@ -1154,8 +1142,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) if (status) goto bail_unlock; - inode_dio_wait(inode); - if (i_size_read(inode) > attr->ia_size) { if (ocfs2_should_order_data(inode)) { status = ocfs2_begin_ordered_truncate(inode, @@ -1293,11 +1279,11 @@ int ocfs2_getattr(struct vfsmount *mnt, return err; } -int ocfs2_permission(struct inode *inode, int mask) +int ocfs2_permission(struct inode *inode, int mask, unsigned int flags) { int ret; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; ret = ocfs2_inode_lock(inode, NULL, 0); @@ -1307,7 +1293,7 @@ int ocfs2_permission(struct inode *inode, int mask) goto out; } - ret = generic_permission(inode, mask); + ret = generic_permission(inode, mask, flags, ocfs2_check_acl); ocfs2_inode_unlock(inode, 0); out: @@ -2250,8 +2236,9 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, ocfs2_iocb_clear_sem_locked(iocb); relock: - /* to match setattr's i_mutex -> rw_lock ordering */ + /* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */ if (direct_io) { + down_read(&inode->i_alloc_sem); have_alloc_sem = 1; /* communicate with ocfs2_dio_end_io */ ocfs2_iocb_set_sem_locked(iocb); @@ -2303,6 +2290,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, */ if (direct_io && !can_do_direct) { ocfs2_rw_unlock(inode, rw_level); + up_read(&inode->i_alloc_sem); have_alloc_sem = 0; rw_level = -1; @@ -2373,7 +2361,8 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, /* * deep in g_f_a_w_n()->ocfs2_direct_IO we pass in a ocfs2_dio_end_io * function pointer which is called when o_direct io completes so that - * it can unlock our rw lock. + * it can unlock our rw lock. (it's the clustered equivalent of + * i_alloc_sem; protects truncate from racing with pending ios). * Unfortunately there are error cases which call end_io and others * that don't. so we don't have to unlock the rw_lock if either an * async dio is going to do it in the future or an end_io after an @@ -2389,8 +2378,10 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, ocfs2_rw_unlock(inode, rw_level); out_sems: - if (have_alloc_sem) + if (have_alloc_sem) { + up_read(&inode->i_alloc_sem); ocfs2_iocb_clear_sem_locked(iocb); + } mutex_unlock(&inode->i_mutex); @@ -2540,6 +2531,7 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, * need locks to protect pending reads from racing with truncate. */ if (filp->f_flags & O_DIRECT) { + down_read(&inode->i_alloc_sem); have_alloc_sem = 1; ocfs2_iocb_set_sem_locked(iocb); @@ -2582,9 +2574,10 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, } bail: - if (have_alloc_sem) + if (have_alloc_sem) { + up_read(&inode->i_alloc_sem); ocfs2_iocb_clear_sem_locked(iocb); - + } if (rw_level != -1) ocfs2_rw_unlock(inode, rw_level); @@ -2600,14 +2593,12 @@ const struct inode_operations ocfs2_file_iops = { .listxattr = ocfs2_listxattr, .removexattr = generic_removexattr, .fiemap = ocfs2_fiemap, - .check_acl = ocfs2_check_acl, }; const struct inode_operations ocfs2_special_file_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, .permission = ocfs2_permission, - .check_acl = ocfs2_check_acl, }; /* diff --git a/trunk/fs/ocfs2/file.h b/trunk/fs/ocfs2/file.h index 97bf761c9e7c..f5afbbef6703 100644 --- a/trunk/fs/ocfs2/file.h +++ b/trunk/fs/ocfs2/file.h @@ -61,7 +61,7 @@ int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh, int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); -int ocfs2_permission(struct inode *inode, int mask); +int ocfs2_permission(struct inode *inode, int mask, unsigned int flags); int ocfs2_should_update_atime(struct inode *inode, struct vfsmount *vfsmnt); diff --git a/trunk/fs/ocfs2/namei.c b/trunk/fs/ocfs2/namei.c index 33889dc52dd7..e5d738cd9cc0 100644 --- a/trunk/fs/ocfs2/namei.c +++ b/trunk/fs/ocfs2/namei.c @@ -2498,5 +2498,4 @@ const struct inode_operations ocfs2_dir_iops = { .listxattr = ocfs2_listxattr, .removexattr = generic_removexattr, .fiemap = ocfs2_fiemap, - .check_acl = ocfs2_check_acl, }; diff --git a/trunk/fs/ocfs2/refcounttree.c b/trunk/fs/ocfs2/refcounttree.c index cf7823382664..ebfd3825f12a 100644 --- a/trunk/fs/ocfs2/refcounttree.c +++ b/trunk/fs/ocfs2/refcounttree.c @@ -4368,6 +4368,25 @@ static inline int ocfs2_may_create(struct inode *dir, struct dentry *child) return inode_permission(dir, MAY_WRITE | MAY_EXEC); } +/* copied from user_path_parent. */ +static int ocfs2_user_path_parent(const char __user *path, + struct nameidata *nd, char **name) +{ + char *s = getname(path); + int error; + + if (IS_ERR(s)) + return PTR_ERR(s); + + error = kern_path_parent(s, nd); + if (error) + putname(s); + else + *name = s; + + return error; +} + /** * ocfs2_vfs_reflink - Create a reference-counted link * @@ -4441,8 +4460,10 @@ int ocfs2_reflink_ioctl(struct inode *inode, bool preserve) { struct dentry *new_dentry; - struct path old_path, new_path; + struct nameidata nd; + struct path old_path; int error; + char *to = NULL; if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) return -EOPNOTSUPP; @@ -4453,33 +4474,39 @@ int ocfs2_reflink_ioctl(struct inode *inode, return error; } - new_dentry = user_path_create(AT_FDCWD, newname, &new_path, 0); - error = PTR_ERR(new_dentry); - if (IS_ERR(new_dentry)) { + error = ocfs2_user_path_parent(newname, &nd, &to); + if (error) { mlog_errno(error); goto out; } error = -EXDEV; - if (old_path.mnt != new_path.mnt) { + if (old_path.mnt != nd.path.mnt) + goto out_release; + new_dentry = lookup_create(&nd, 0); + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) { mlog_errno(error); - goto out_dput; + goto out_unlock; } - error = mnt_want_write(new_path.mnt); + error = mnt_want_write(nd.path.mnt); if (error) { mlog_errno(error); goto out_dput; } error = ocfs2_vfs_reflink(old_path.dentry, - new_path.dentry->d_inode, + nd.path.dentry->d_inode, new_dentry, preserve); - mnt_drop_write(new_path.mnt); + mnt_drop_write(nd.path.mnt); out_dput: dput(new_dentry); - mutex_unlock(&new_path.dentry->d_inode->i_mutex); - path_put(&new_path); +out_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); +out_release: + path_put(&nd.path); + putname(to); out: path_put(&old_path); diff --git a/trunk/fs/open.c b/trunk/fs/open.c index 739b751aa73e..b52cf013ffa1 100644 --- a/trunk/fs/open.c +++ b/trunk/fs/open.c @@ -793,7 +793,7 @@ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry return nd->intent.open.file; out_err: release_open_intent(nd); - nd->intent.open.file = ERR_CAST(dentry); + nd->intent.open.file = (struct file *)dentry; goto out; } EXPORT_SYMBOL_GPL(lookup_instantiate_filp); diff --git a/trunk/fs/proc/base.c b/trunk/fs/proc/base.c index 91fb655a5cbf..c47719aaadef 100644 --- a/trunk/fs/proc/base.c +++ b/trunk/fs/proc/base.c @@ -673,7 +673,7 @@ static int mounts_open_common(struct inode *inode, struct file *file, p->m.private = p; p->ns = ns; p->root = root; - p->m.poll_event = ns->event; + p->event = ns->event; return 0; @@ -2167,9 +2167,9 @@ static const struct file_operations proc_fd_operations = { * /proc/pid/fd needs a special permission handler so that a process can still * access /proc/self/fd after it has executed a setuid(). */ -static int proc_fd_permission(struct inode *inode, int mask) +static int proc_fd_permission(struct inode *inode, int mask, unsigned int flags) { - int rv = generic_permission(inode, mask); + int rv = generic_permission(inode, mask, flags, NULL); if (rv == 0) return 0; if (task_pid(current) == proc_pid(inode)) diff --git a/trunk/fs/proc/proc_sysctl.c b/trunk/fs/proc/proc_sysctl.c index 1a77dbef226f..d167de365a8d 100644 --- a/trunk/fs/proc/proc_sysctl.c +++ b/trunk/fs/proc/proc_sysctl.c @@ -294,7 +294,7 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) return ret; } -static int proc_sys_permission(struct inode *inode, int mask) +static int proc_sys_permission(struct inode *inode, int mask,unsigned int flags) { /* * sysctl entries that are not writeable, @@ -316,7 +316,7 @@ static int proc_sys_permission(struct inode *inode, int mask) if (!table) /* global root - r-xr-xr-x */ error = mask & MAY_WRITE ? -EACCES : 0; else /* Use the permissions on the sysctl table entry */ - error = sysctl_perm(head->root, table, mask & ~MAY_NOT_BLOCK); + error = sysctl_perm(head->root, table, mask); sysctl_head_finish(head); return error; diff --git a/trunk/fs/read_write.c b/trunk/fs/read_write.c index 5907b49e4d7e..5520f8ad5504 100644 --- a/trunk/fs/read_write.c +++ b/trunk/fs/read_write.c @@ -64,23 +64,6 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) return file->f_pos; offset += file->f_pos; break; - case SEEK_DATA: - /* - * In the generic case the entire file is data, so as long as - * offset isn't at the end of the file then the offset is data. - */ - if (offset >= inode->i_size) - return -ENXIO; - break; - case SEEK_HOLE: - /* - * There is a virtual hole at the end of the file, so as long as - * offset isn't i_size or larger, return i_size. - */ - if (offset >= inode->i_size) - return -ENXIO; - offset = inode->i_size; - break; } if (offset < 0 && !unsigned_offsets(file)) @@ -145,13 +128,12 @@ EXPORT_SYMBOL(no_llseek); loff_t default_llseek(struct file *file, loff_t offset, int origin) { - struct inode *inode = file->f_path.dentry->d_inode; loff_t retval; - mutex_lock(&inode->i_mutex); + mutex_lock(&file->f_dentry->d_inode->i_mutex); switch (origin) { case SEEK_END: - offset += i_size_read(inode); + offset += i_size_read(file->f_path.dentry->d_inode); break; case SEEK_CUR: if (offset == 0) { @@ -159,26 +141,6 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) goto out; } offset += file->f_pos; - break; - case SEEK_DATA: - /* - * In the generic case the entire file is data, so as - * long as offset isn't at the end of the file then the - * offset is data. - */ - if (offset >= inode->i_size) - return -ENXIO; - break; - case SEEK_HOLE: - /* - * There is a virtual hole at the end of the file, so - * as long as offset isn't i_size or larger, return - * i_size. - */ - if (offset >= inode->i_size) - return -ENXIO; - offset = inode->i_size; - break; } retval = -EINVAL; if (offset >= 0 || unsigned_offsets(file)) { @@ -189,7 +151,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) retval = offset; } out: - mutex_unlock(&inode->i_mutex); + mutex_unlock(&file->f_dentry->d_inode->i_mutex); return retval; } EXPORT_SYMBOL(default_llseek); diff --git a/trunk/fs/reiserfs/dir.c b/trunk/fs/reiserfs/dir.c index 133e9355dc6f..198dabf1b2bb 100644 --- a/trunk/fs/reiserfs/dir.c +++ b/trunk/fs/reiserfs/dir.c @@ -14,8 +14,7 @@ extern const struct reiserfs_key MIN_KEY; static int reiserfs_readdir(struct file *, void *, filldir_t); -static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end, - int datasync); +static int reiserfs_dir_fsync(struct file *filp, int datasync); const struct file_operations reiserfs_dir_operations = { .llseek = generic_file_llseek, @@ -28,21 +27,13 @@ const struct file_operations reiserfs_dir_operations = { #endif }; -static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end, - int datasync) +static int reiserfs_dir_fsync(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; int err; - - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - mutex_lock(&inode->i_mutex); reiserfs_write_lock(inode->i_sb); err = reiserfs_commit_for_inode(inode); reiserfs_write_unlock(inode->i_sb); - mutex_unlock(&inode->i_mutex); if (err < 0) return err; return 0; diff --git a/trunk/fs/reiserfs/file.c b/trunk/fs/reiserfs/file.c index c7156dc39ce7..91f080cc76c8 100644 --- a/trunk/fs/reiserfs/file.c +++ b/trunk/fs/reiserfs/file.c @@ -140,18 +140,12 @@ static void reiserfs_vfs_truncate_file(struct inode *inode) * be removed... */ -static int reiserfs_sync_file(struct file *filp, loff_t start, loff_t end, - int datasync) +static int reiserfs_sync_file(struct file *filp, int datasync) { struct inode *inode = filp->f_mapping->host; int err; int barrier_done; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - mutex_lock(&inode->i_mutex); BUG_ON(!S_ISREG(inode->i_mode)); err = sync_mapping_buffers(inode->i_mapping); reiserfs_write_lock(inode->i_sb); @@ -159,7 +153,6 @@ static int reiserfs_sync_file(struct file *filp, loff_t start, loff_t end, reiserfs_write_unlock(inode->i_sb); if (barrier_done != 1 && reiserfs_barrier_flush(inode->i_sb)) blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); - mutex_unlock(&inode->i_mutex); if (barrier_done < 0) return barrier_done; return (err < 0) ? -EIO : 0; @@ -319,5 +312,4 @@ const struct inode_operations reiserfs_file_inode_operations = { .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, - .check_acl = reiserfs_check_acl, }; diff --git a/trunk/fs/reiserfs/inode.c b/trunk/fs/reiserfs/inode.c index 2922b90ceac1..4fd5bb33dbb5 100644 --- a/trunk/fs/reiserfs/inode.c +++ b/trunk/fs/reiserfs/inode.c @@ -3068,8 +3068,9 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, struct inode *inode = file->f_mapping->host; ssize_t ret; - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - reiserfs_get_blocks_direct_io); + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, + reiserfs_get_blocks_direct_io, NULL); /* * In case of error extending write may have instantiated a few @@ -3113,9 +3114,6 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) error = -EFBIG; goto out; } - - inode_dio_wait(inode); - /* fill in hole pointers in the expanding truncate case. */ if (attr->ia_size > inode->i_size) { error = generic_cont_expand_simple(inode, attr->ia_size); diff --git a/trunk/fs/reiserfs/namei.c b/trunk/fs/reiserfs/namei.c index 551f1b79dbc4..118662690cdf 100644 --- a/trunk/fs/reiserfs/namei.c +++ b/trunk/fs/reiserfs/namei.c @@ -1529,7 +1529,6 @@ const struct inode_operations reiserfs_dir_inode_operations = { .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, - .check_acl = reiserfs_check_acl, }; /* @@ -1546,7 +1545,6 @@ const struct inode_operations reiserfs_symlink_inode_operations = { .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, - .check_acl = reiserfs_check_acl, }; @@ -1560,5 +1558,5 @@ const struct inode_operations reiserfs_special_inode_operations = { .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, - .check_acl = reiserfs_check_acl, + }; diff --git a/trunk/fs/reiserfs/super.c b/trunk/fs/reiserfs/super.c index 14363b96b6af..aa91089162cb 100644 --- a/trunk/fs/reiserfs/super.c +++ b/trunk/fs/reiserfs/super.c @@ -1643,7 +1643,6 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) /* Set default values for options: non-aggressive tails, RO on errors */ REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_SMALLTAIL); REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ERROR_RO); - REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_BARRIER_FLUSH); /* no preallocation minimum, be smart in reiserfs_file_write instead */ REISERFS_SB(s)->s_alloc_options.preallocmin = 0; diff --git a/trunk/fs/reiserfs/xattr.c b/trunk/fs/reiserfs/xattr.c index 6938d8c68d6e..d78089690965 100644 --- a/trunk/fs/reiserfs/xattr.c +++ b/trunk/fs/reiserfs/xattr.c @@ -555,10 +555,11 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, reiserfs_write_unlock(inode->i_sb); mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); - inode_dio_wait(dentry->d_inode); + down_write(&dentry->d_inode->i_alloc_sem); reiserfs_write_lock(inode->i_sb); err = reiserfs_setattr(dentry, &newattrs); + up_write(&dentry->d_inode->i_alloc_sem); mutex_unlock(&dentry->d_inode->i_mutex); } else update_ctime(inode); @@ -867,18 +868,12 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) return err; } -int reiserfs_check_acl(struct inode *inode, int mask) +static int reiserfs_check_acl(struct inode *inode, int mask, unsigned int flags) { struct posix_acl *acl; int error = -EAGAIN; /* do regular unix permission checks by default */ - /* - * Stat data v1 doesn't support ACLs. - */ - if (get_inode_sd_version(inode) == STAT_DATA_V1) - return -EAGAIN; - - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); @@ -957,7 +952,7 @@ static int xattr_mount_check(struct super_block *s) return 0; } -int reiserfs_permission(struct inode *inode, int mask) +int reiserfs_permission(struct inode *inode, int mask, unsigned int flags) { /* * We don't do permission checks on the internal objects. @@ -966,7 +961,15 @@ int reiserfs_permission(struct inode *inode, int mask) if (IS_PRIVATE(inode)) return 0; - return generic_permission(inode, mask); +#ifdef CONFIG_REISERFS_FS_XATTR + /* + * Stat data v1 doesn't support ACLs. + */ + if (get_inode_sd_version(inode) != STAT_DATA_V1) + return generic_permission(inode, mask, flags, + reiserfs_check_acl); +#endif + return generic_permission(inode, mask, flags, NULL); } static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd) diff --git a/trunk/fs/squashfs/namei.c b/trunk/fs/squashfs/namei.c index 0682b38d7e31..4bc63ac64bc0 100644 --- a/trunk/fs/squashfs/namei.c +++ b/trunk/fs/squashfs/namei.c @@ -220,6 +220,11 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry, blk, off, ino_num); inode = squashfs_iget(dir->i_sb, ino, ino_num); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto failed; + } + goto exit_lookup; } } @@ -227,7 +232,10 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry, exit_lookup: kfree(dire); - return d_splice_alias(inode, dentry); + if (inode) + return d_splice_alias(inode, dentry); + d_add(dentry, inode); + return ERR_PTR(0); data_error: err = -EIO; diff --git a/trunk/fs/super.c b/trunk/fs/super.c index 7943f04cb3a9..ab3d672db0de 100644 --- a/trunk/fs/super.c +++ b/trunk/fs/super.c @@ -38,69 +38,6 @@ LIST_HEAD(super_blocks); DEFINE_SPINLOCK(sb_lock); -/* - * One thing we have to be careful of with a per-sb shrinker is that we don't - * drop the last active reference to the superblock from within the shrinker. - * If that happens we could trigger unregistering the shrinker from within the - * shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we - * take a passive reference to the superblock to avoid this from occurring. - */ -static int prune_super(struct shrinker *shrink, struct shrink_control *sc) -{ - struct super_block *sb; - int fs_objects = 0; - int total_objects; - - sb = container_of(shrink, struct super_block, s_shrink); - - /* - * Deadlock avoidance. We may hold various FS locks, and we don't want - * to recurse into the FS that called us in clear_inode() and friends.. - */ - if (sc->nr_to_scan && !(sc->gfp_mask & __GFP_FS)) - return -1; - - if (!grab_super_passive(sb)) - return -1; - - if (sb->s_op && sb->s_op->nr_cached_objects) - fs_objects = sb->s_op->nr_cached_objects(sb); - - total_objects = sb->s_nr_dentry_unused + - sb->s_nr_inodes_unused + fs_objects + 1; - - if (sc->nr_to_scan) { - int dentries; - int inodes; - - /* proportion the scan between the caches */ - dentries = (sc->nr_to_scan * sb->s_nr_dentry_unused) / - total_objects; - inodes = (sc->nr_to_scan * sb->s_nr_inodes_unused) / - total_objects; - if (fs_objects) - fs_objects = (sc->nr_to_scan * fs_objects) / - total_objects; - /* - * prune the dcache first as the icache is pinned by it, then - * prune the icache, followed by the filesystem specific caches - */ - prune_dcache_sb(sb, dentries); - prune_icache_sb(sb, inodes); - - if (fs_objects && sb->s_op->free_cached_objects) { - sb->s_op->free_cached_objects(sb, fs_objects); - fs_objects = sb->s_op->nr_cached_objects(sb); - } - total_objects = sb->s_nr_dentry_unused + - sb->s_nr_inodes_unused + fs_objects; - } - - total_objects = (total_objects / 100) * sysctl_vfs_cache_pressure; - drop_super(sb); - return total_objects; -} - /** * alloc_super - create new superblock * @type: filesystem type superblock should belong to @@ -140,8 +77,6 @@ static struct super_block *alloc_super(struct file_system_type *type) INIT_HLIST_BL_HEAD(&s->s_anon); INIT_LIST_HEAD(&s->s_inodes); INIT_LIST_HEAD(&s->s_dentry_lru); - INIT_LIST_HEAD(&s->s_inode_lru); - spin_lock_init(&s->s_inode_lru_lock); init_rwsem(&s->s_umount); mutex_init(&s->s_lock); lockdep_set_class(&s->s_umount, &type->s_umount_key); @@ -179,10 +114,6 @@ static struct super_block *alloc_super(struct file_system_type *type) s->s_op = &default_op; s->s_time_gran = 1000000000; s->cleancache_poolid = -1; - - s->s_shrink.seeks = DEFAULT_SEEKS; - s->s_shrink.shrink = prune_super; - s->s_shrink.batch = 1024; } out: return s; @@ -250,10 +181,6 @@ void deactivate_locked_super(struct super_block *s) if (atomic_dec_and_test(&s->s_active)) { cleancache_flush_fs(s); fs->kill_sb(s); - - /* caches are now gone, we can safely kill the shrinker now */ - unregister_shrinker(&s->s_shrink); - /* * We need to call rcu_barrier so all the delayed rcu free * inodes are flushed before we release the fs module. @@ -313,39 +240,6 @@ static int grab_super(struct super_block *s) __releases(sb_lock) return 0; } -/* - * grab_super_passive - acquire a passive reference - * @s: reference we are trying to grab - * - * Tries to acquire a passive reference. This is used in places where we - * cannot take an active reference but we need to ensure that the - * superblock does not go away while we are working on it. It returns - * false if a reference was not gained, and returns true with the s_umount - * lock held in read mode if a reference is gained. On successful return, - * the caller must drop the s_umount lock and the passive reference when - * done. - */ -bool grab_super_passive(struct super_block *sb) -{ - spin_lock(&sb_lock); - if (list_empty(&sb->s_instances)) { - spin_unlock(&sb_lock); - return false; - } - - sb->s_count++; - spin_unlock(&sb_lock); - - if (down_read_trylock(&sb->s_umount)) { - if (sb->s_root) - return true; - up_read(&sb->s_umount); - } - - put_super(sb); - return false; -} - /* * Superblock locking. We really ought to get rid of these two. */ @@ -382,6 +276,7 @@ void generic_shutdown_super(struct super_block *sb) { const struct super_operations *sop = sb->s_op; + if (sb->s_root) { shrink_dcache_for_umount(sb); sync_filesystem(sb); @@ -469,7 +364,6 @@ struct super_block *sget(struct file_system_type *type, list_add(&s->s_instances, &type->fs_supers); spin_unlock(&sb_lock); get_filesystem(type); - register_shrinker(&s->s_shrink); return s; } @@ -557,42 +451,6 @@ void iterate_supers(void (*f)(struct super_block *, void *), void *arg) spin_unlock(&sb_lock); } -/** - * iterate_supers_type - call function for superblocks of given type - * @type: fs type - * @f: function to call - * @arg: argument to pass to it - * - * Scans the superblock list and calls given function, passing it - * locked superblock and given argument. - */ -void iterate_supers_type(struct file_system_type *type, - void (*f)(struct super_block *, void *), void *arg) -{ - struct super_block *sb, *p = NULL; - - spin_lock(&sb_lock); - list_for_each_entry(sb, &type->fs_supers, s_instances) { - sb->s_count++; - spin_unlock(&sb_lock); - - down_read(&sb->s_umount); - if (sb->s_root) - f(sb, arg); - up_read(&sb->s_umount); - - spin_lock(&sb_lock); - if (p) - __put_super(p); - p = sb; - } - if (p) - __put_super(p); - spin_unlock(&sb_lock); -} - -EXPORT_SYMBOL(iterate_supers_type); - /** * get_super - get the superblock of a device * @bdev: device to get the superblock for @@ -799,7 +657,7 @@ static DEFINE_IDA(unnamed_dev_ida); static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */ static int unnamed_dev_start = 0; /* don't bother trying below it */ -int get_anon_bdev(dev_t *p) +int set_anon_super(struct super_block *s, void *data) { int dev; int error; @@ -826,38 +684,24 @@ int get_anon_bdev(dev_t *p) spin_unlock(&unnamed_dev_lock); return -EMFILE; } - *p = MKDEV(0, dev & MINORMASK); + s->s_dev = MKDEV(0, dev & MINORMASK); + s->s_bdi = &noop_backing_dev_info; return 0; } -EXPORT_SYMBOL(get_anon_bdev); -void free_anon_bdev(dev_t dev) +EXPORT_SYMBOL(set_anon_super); + +void kill_anon_super(struct super_block *sb) { - int slot = MINOR(dev); + int slot = MINOR(sb->s_dev); + + generic_shutdown_super(sb); spin_lock(&unnamed_dev_lock); ida_remove(&unnamed_dev_ida, slot); if (slot < unnamed_dev_start) unnamed_dev_start = slot; spin_unlock(&unnamed_dev_lock); } -EXPORT_SYMBOL(free_anon_bdev); - -int set_anon_super(struct super_block *s, void *data) -{ - int error = get_anon_bdev(&s->s_dev); - if (!error) - s->s_bdi = &noop_backing_dev_info; - return error; -} - -EXPORT_SYMBOL(set_anon_super); - -void kill_anon_super(struct super_block *sb) -{ - dev_t dev = sb->s_dev; - generic_shutdown_super(sb); - free_anon_bdev(dev); -} EXPORT_SYMBOL(kill_anon_super); diff --git a/trunk/fs/sync.c b/trunk/fs/sync.c index c98a7477edfd..c38ec163da6c 100644 --- a/trunk/fs/sync.c +++ b/trunk/fs/sync.c @@ -165,9 +165,28 @@ SYSCALL_DEFINE1(syncfs, int, fd) */ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync) { - if (!file->f_op || !file->f_op->fsync) - return -EINVAL; - return file->f_op->fsync(file, start, end, datasync); + struct address_space *mapping = file->f_mapping; + int err, ret; + + if (!file->f_op || !file->f_op->fsync) { + ret = -EINVAL; + goto out; + } + + ret = filemap_write_and_wait_range(mapping, start, end); + + /* + * We need to protect against concurrent writers, which could cause + * livelocks in fsync_buffers_list(). + */ + mutex_lock(&mapping->host->i_mutex); + err = file->f_op->fsync(file, datasync); + if (!ret) + ret = err; + mutex_unlock(&mapping->host->i_mutex); + +out: + return ret; } EXPORT_SYMBOL(vfs_fsync_range); diff --git a/trunk/fs/sysfs/inode.c b/trunk/fs/sysfs/inode.c index e3f091a81c72..0a12eb89cd32 100644 --- a/trunk/fs/sysfs/inode.c +++ b/trunk/fs/sysfs/inode.c @@ -349,11 +349,11 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const cha return -ENOENT; } -int sysfs_permission(struct inode *inode, int mask) +int sysfs_permission(struct inode *inode, int mask, unsigned int flags) { struct sysfs_dirent *sd; - if (mask & MAY_NOT_BLOCK) + if (flags & IPERM_FLAG_RCU) return -ECHILD; sd = inode->i_private; @@ -362,5 +362,5 @@ int sysfs_permission(struct inode *inode, int mask) sysfs_refresh_inode(sd, inode); mutex_unlock(&sysfs_mutex); - return generic_permission(inode, mask); + return generic_permission(inode, mask, flags, NULL); } diff --git a/trunk/fs/sysfs/sysfs.h b/trunk/fs/sysfs/sysfs.h index 845ab3ad229d..2ed2404f3113 100644 --- a/trunk/fs/sysfs/sysfs.h +++ b/trunk/fs/sysfs/sysfs.h @@ -201,7 +201,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); void sysfs_evict_inode(struct inode *inode); int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); -int sysfs_permission(struct inode *inode, int mask); +int sysfs_permission(struct inode *inode, int mask, unsigned int flags); int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, diff --git a/trunk/fs/ubifs/file.c b/trunk/fs/ubifs/file.c index f9c234bf33d3..7cf738a4544d 100644 --- a/trunk/fs/ubifs/file.c +++ b/trunk/fs/ubifs/file.c @@ -1304,7 +1304,7 @@ static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) +int ubifs_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; struct ubifs_info *c = inode->i_sb->s_fs_info; @@ -1319,16 +1319,14 @@ int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) */ return 0; - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - mutex_lock(&inode->i_mutex); - - /* Synchronize the inode unless this is a 'datasync()' call. */ + /* + * VFS has already synchronized dirty pages for this inode. Synchronize + * the inode unless this is a 'datasync()' call. + */ if (!datasync || (inode->i_state & I_DIRTY_DATASYNC)) { err = inode->i_sb->s_op->write_inode(inode, NULL); if (err) - goto out; + return err; } /* @@ -1336,9 +1334,10 @@ int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) * them. */ err = ubifs_sync_wbufs_by_inode(c, inode); -out: - mutex_unlock(&inode->i_mutex); - return err; + if (err) + return err; + + return 0; } /** diff --git a/trunk/fs/ubifs/ubifs.h b/trunk/fs/ubifs/ubifs.h index 27f22551f805..702b79258e30 100644 --- a/trunk/fs/ubifs/ubifs.h +++ b/trunk/fs/ubifs/ubifs.h @@ -1729,7 +1729,7 @@ const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c); int ubifs_calc_dark(const struct ubifs_info *c, int spc); /* file.c */ -int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync); +int ubifs_fsync(struct file *file, int datasync); int ubifs_setattr(struct dentry *dentry, struct iattr *attr); /* dir.c */ diff --git a/trunk/fs/udf/file.c b/trunk/fs/udf/file.c index d8ffa7cc661d..2a346bb1d9f5 100644 --- a/trunk/fs/udf/file.c +++ b/trunk/fs/udf/file.c @@ -150,7 +150,7 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) long old_block, new_block; int result = -EINVAL; - if (inode_permission(inode, MAY_READ) != 0) { + if (file_permission(filp, MAY_READ) != 0) { udf_debug("no permission to access inode %lu\n", inode->i_ino); result = -EPERM; goto out; diff --git a/trunk/fs/ufs/namei.c b/trunk/fs/ufs/namei.c index 639d49162241..b57aab9a1184 100644 --- a/trunk/fs/ufs/namei.c +++ b/trunk/fs/ufs/namei.c @@ -59,6 +59,8 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru if (ino) inode = ufs_iget(dir->i_sb, ino); unlock_ufs(dir->i_sb); + if (IS_ERR(inode)) + return ERR_CAST(inode); return d_splice_alias(inode, dentry); } diff --git a/trunk/fs/xfs/linux-2.6/xfs_acl.c b/trunk/fs/xfs/linux-2.6/xfs_acl.c index cac48fe22ad5..115ac6919533 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_acl.c +++ b/trunk/fs/xfs/linux-2.6/xfs_acl.c @@ -219,7 +219,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) } int -xfs_check_acl(struct inode *inode, int mask) +xfs_check_acl(struct inode *inode, int mask, unsigned int flags) { struct xfs_inode *ip; struct posix_acl *acl; @@ -235,7 +235,7 @@ xfs_check_acl(struct inode *inode, int mask) if (!XFS_IFORK_Q(ip)) return -EAGAIN; - if (mask & MAY_NOT_BLOCK) { + if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; return -EAGAIN; diff --git a/trunk/fs/xfs/linux-2.6/xfs_aops.c b/trunk/fs/xfs/linux-2.6/xfs_aops.c index 63e971e2b837..26384fe3f26d 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_aops.c +++ b/trunk/fs/xfs/linux-2.6/xfs_aops.c @@ -1329,9 +1329,6 @@ xfs_end_io_direct_write( } else { xfs_finish_ioend_sync(ioend); } - - /* XXX: probably should move into the real I/O completion handler */ - inode_dio_done(ioend->io_inode); } STATIC ssize_t diff --git a/trunk/fs/xfs/linux-2.6/xfs_file.c b/trunk/fs/xfs/linux-2.6/xfs_file.c index cca00f49e092..8073f61efb8e 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_file.c +++ b/trunk/fs/xfs/linux-2.6/xfs_file.c @@ -127,8 +127,6 @@ xfs_iozero( STATIC int xfs_file_fsync( struct file *file, - loff_t start, - loff_t end, int datasync) { struct inode *inode = file->f_mapping->host; @@ -140,10 +138,6 @@ xfs_file_fsync( trace_xfs_file_fsync(ip); - error = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (error) - return error; - if (XFS_FORCED_SHUTDOWN(mp)) return -XFS_ERROR(EIO); @@ -881,11 +875,18 @@ xfs_file_aio_write( /* Handle various SYNC-type writes */ if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) { loff_t end = pos + ret - 1; + int error, error2; xfs_rw_iunlock(ip, iolock); - ret = -xfs_file_fsync(file, pos, end, - (file->f_flags & __O_SYNC) ? 0 : 1); + error = filemap_write_and_wait_range(mapping, pos, end); xfs_rw_ilock(ip, iolock); + + error2 = -xfs_file_fsync(file, + (file->f_flags & __O_SYNC) ? 0 : 1); + if (error) + ret = error; + else if (error2) + ret = error2; } out_unlock: diff --git a/trunk/fs/xfs/linux-2.6/xfs_super.c b/trunk/fs/xfs/linux-2.6/xfs_super.c index 9a72dda58bd0..25fd2cd6c8b0 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_super.c +++ b/trunk/fs/xfs/linux-2.6/xfs_super.c @@ -1024,6 +1024,11 @@ xfs_fs_put_super( { struct xfs_mount *mp = XFS_M(sb); + /* + * Unregister the memory shrinker before we tear down the mount + * structure so we don't have memory reclaim racing with us here. + */ + xfs_inode_shrinker_unregister(mp); xfs_syncd_stop(mp); /* @@ -1406,6 +1411,8 @@ xfs_fs_fill_super( sb->s_time_gran = 1; set_posix_acl_flag(sb); + xfs_inode_shrinker_register(mp); + error = xfs_mountfs(mp); if (error) goto out_filestream_unmount; @@ -1432,6 +1439,7 @@ xfs_fs_fill_super( return 0; out_filestream_unmount: + xfs_inode_shrinker_unregister(mp); xfs_filestream_unmount(mp); out_free_sb: xfs_freesb(mp); @@ -1450,6 +1458,8 @@ xfs_fs_fill_super( out_syncd_stop: xfs_syncd_stop(mp); out_unmount: + xfs_inode_shrinker_unregister(mp); + /* * Blow away any referenced inode in the filestreams cache. * This can and will cause log traffic as inodes go inactive @@ -1473,21 +1483,6 @@ xfs_fs_mount( return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super); } -static int -xfs_fs_nr_cached_objects( - struct super_block *sb) -{ - return xfs_reclaim_inodes_count(XFS_M(sb)); -} - -static void -xfs_fs_free_cached_objects( - struct super_block *sb, - int nr_to_scan) -{ - xfs_reclaim_inodes_nr(XFS_M(sb), nr_to_scan); -} - static const struct super_operations xfs_super_operations = { .alloc_inode = xfs_fs_alloc_inode, .destroy_inode = xfs_fs_destroy_inode, @@ -1501,8 +1496,6 @@ static const struct super_operations xfs_super_operations = { .statfs = xfs_fs_statfs, .remount_fs = xfs_fs_remount, .show_options = xfs_fs_show_options, - .nr_cached_objects = xfs_fs_nr_cached_objects, - .free_cached_objects = xfs_fs_free_cached_objects, }; static struct file_system_type xfs_fs_type = { diff --git a/trunk/fs/xfs/linux-2.6/xfs_sync.c b/trunk/fs/xfs/linux-2.6/xfs_sync.c index e4c938afb910..5cc158e52d4c 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_sync.c +++ b/trunk/fs/xfs/linux-2.6/xfs_sync.c @@ -179,8 +179,6 @@ xfs_inode_ag_walk( if (error == EFSCORRUPTED) break; - cond_resched(); - } while (nr_found && !done); if (skipped) { @@ -986,8 +984,6 @@ xfs_reclaim_inodes_ag( *nr_to_scan -= XFS_LOOKUP_BATCH; - cond_resched(); - } while (nr_found && !done && *nr_to_scan > 0); if (trylock && !done) @@ -1005,7 +1001,7 @@ xfs_reclaim_inodes_ag( * ensure that when we get more reclaimers than AGs we block rather * than spin trying to execute reclaim. */ - if (skipped && (flags & SYNC_WAIT) && *nr_to_scan > 0) { + if (trylock && skipped && *nr_to_scan > 0) { trylock = 0; goto restart; } @@ -1023,38 +1019,44 @@ xfs_reclaim_inodes( } /* - * Scan a certain number of inodes for reclaim. + * Inode cache shrinker. * * When called we make sure that there is a background (fast) inode reclaim in - * progress, while we will throttle the speed of reclaim via doing synchronous + * progress, while we will throttle the speed of reclaim via doiing synchronous * reclaim of inodes. That means if we come across dirty inodes, we wait for * them to be cleaned, which we hope will not be very long due to the * background walker having already kicked the IO off on those dirty inodes. */ -void -xfs_reclaim_inodes_nr( - struct xfs_mount *mp, - int nr_to_scan) +static int +xfs_reclaim_inode_shrink( + struct shrinker *shrink, + struct shrink_control *sc) { - /* kick background reclaimer and push the AIL */ - xfs_syncd_queue_reclaim(mp); - xfs_ail_push_all(mp->m_ail); + struct xfs_mount *mp; + struct xfs_perag *pag; + xfs_agnumber_t ag; + int reclaimable; + int nr_to_scan = sc->nr_to_scan; + gfp_t gfp_mask = sc->gfp_mask; + + mp = container_of(shrink, struct xfs_mount, m_inode_shrink); + if (nr_to_scan) { + /* kick background reclaimer and push the AIL */ + xfs_syncd_queue_reclaim(mp); + xfs_ail_push_all(mp->m_ail); - xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan); -} + if (!(gfp_mask & __GFP_FS)) + return -1; -/* - * Return the number of reclaimable inodes in the filesystem for - * the shrinker to determine how much to reclaim. - */ -int -xfs_reclaim_inodes_count( - struct xfs_mount *mp) -{ - struct xfs_perag *pag; - xfs_agnumber_t ag = 0; - int reclaimable = 0; + xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, + &nr_to_scan); + /* terminate if we don't exhaust the scan */ + if (nr_to_scan > 0) + return -1; + } + reclaimable = 0; + ag = 0; while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) { ag = pag->pag_agno + 1; reclaimable += pag->pag_ici_reclaimable; @@ -1063,3 +1065,18 @@ xfs_reclaim_inodes_count( return reclaimable; } +void +xfs_inode_shrinker_register( + struct xfs_mount *mp) +{ + mp->m_inode_shrink.shrink = xfs_reclaim_inode_shrink; + mp->m_inode_shrink.seeks = DEFAULT_SEEKS; + register_shrinker(&mp->m_inode_shrink); +} + +void +xfs_inode_shrinker_unregister( + struct xfs_mount *mp) +{ + unregister_shrinker(&mp->m_inode_shrink); +} diff --git a/trunk/fs/xfs/linux-2.6/xfs_sync.h b/trunk/fs/xfs/linux-2.6/xfs_sync.h index 941202e7ac6e..e914fd621746 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_sync.h +++ b/trunk/fs/xfs/linux-2.6/xfs_sync.h @@ -35,8 +35,6 @@ void xfs_quiesce_attr(struct xfs_mount *mp); void xfs_flush_inodes(struct xfs_inode *ip); int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); -int xfs_reclaim_inodes_count(struct xfs_mount *mp); -void xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan); void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip); @@ -48,4 +46,7 @@ int xfs_inode_ag_iterator(struct xfs_mount *mp, int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags), int flags); +void xfs_inode_shrinker_register(struct xfs_mount *mp); +void xfs_inode_shrinker_unregister(struct xfs_mount *mp); + #endif diff --git a/trunk/fs/xfs/xfs_acl.h b/trunk/fs/xfs/xfs_acl.h index 0135e2a669d7..11dd72070cbb 100644 --- a/trunk/fs/xfs/xfs_acl.h +++ b/trunk/fs/xfs/xfs_acl.h @@ -42,7 +42,7 @@ struct xfs_acl { #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) #ifdef CONFIG_XFS_POSIX_ACL -extern int xfs_check_acl(struct inode *inode, int mask); +extern int xfs_check_acl(struct inode *inode, int mask, unsigned int flags); extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); extern int xfs_acl_chmod(struct inode *inode); diff --git a/trunk/include/linux/anon_inodes.h b/trunk/include/linux/anon_inodes.h index 8013a45242fe..69a21e0ebd33 100644 --- a/trunk/include/linux/anon_inodes.h +++ b/trunk/include/linux/anon_inodes.h @@ -8,8 +8,6 @@ #ifndef _LINUX_ANON_INODES_H #define _LINUX_ANON_INODES_H -struct file_operations; - struct file *anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags); diff --git a/trunk/include/linux/atomic.h b/trunk/include/linux/atomic.h index bc6615d4132b..ee456c79b0e6 100644 --- a/trunk/include/linux/atomic.h +++ b/trunk/include/linux/atomic.h @@ -34,32 +34,6 @@ static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint) } #endif -#ifndef atomic_inc_unless_negative -static inline int atomic_inc_unless_negative(atomic_t *p) -{ - int v, v1; - for (v = 0; v >= 0; v = v1) { - v1 = atomic_cmpxchg(p, v, v + 1); - if (likely(v1 == v)) - return 1; - } - return 0; -} -#endif - -#ifndef atomic_dec_unless_positive -static inline int atomic_dec_unless_positive(atomic_t *p) -{ - int v, v1; - for (v = 0; v <= 0; v = v1) { - v1 = atomic_cmpxchg(p, v, v - 1); - if (likely(v1 == v)) - return 1; - } - return 0; -} -#endif - #ifndef CONFIG_ARCH_HAS_ATOMIC_OR static inline void atomic_or(int i, atomic_t *v) { diff --git a/trunk/include/linux/binfmts.h b/trunk/include/linux/binfmts.h index fd88a3945aa1..8845613fd7e3 100644 --- a/trunk/include/linux/binfmts.h +++ b/trunk/include/linux/binfmts.h @@ -111,7 +111,6 @@ extern int __must_check remove_arg_zero(struct linux_binprm *); extern int search_binary_handler(struct linux_binprm *, struct pt_regs *); extern int flush_old_exec(struct linux_binprm * bprm); extern void setup_new_exec(struct linux_binprm * bprm); -extern void would_dump(struct linux_binprm *, struct file *); extern int suid_dumpable; #define SUID_DUMP_DISABLE 0 /* No setuid dumping */ diff --git a/trunk/include/linux/dcache.h b/trunk/include/linux/dcache.h index 3f22d8d6d8a3..19d90a55541d 100644 --- a/trunk/include/linux/dcache.h +++ b/trunk/include/linux/dcache.h @@ -216,7 +216,6 @@ struct dentry_operations { #define DCACHE_MOUNTED 0x10000 /* is a mountpoint */ #define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */ #define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */ -#define DCACHE_NEED_LOOKUP 0x80000 /* dentry requires i_op->lookup */ #define DCACHE_MANAGED_DENTRY \ (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) @@ -417,12 +416,7 @@ static inline bool d_mountpoint(struct dentry *dentry) return dentry->d_flags & DCACHE_MOUNTED; } -static inline bool d_need_lookup(struct dentry *dentry) -{ - return dentry->d_flags & DCACHE_NEED_LOOKUP; -} - -extern void d_clear_need_lookup(struct dentry *dentry); +extern struct dentry *lookup_create(struct nameidata *nd, int is_dir); extern int sysctl_vfs_cache_pressure; diff --git a/trunk/include/linux/dw_apb_timer.h b/trunk/include/linux/dw_apb_timer.h deleted file mode 100644 index 49638ea3b776..000000000000 --- a/trunk/include/linux/dw_apb_timer.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * (C) Copyright 2009 Intel Corporation - * Author: Jacob Pan (jacob.jun.pan@intel.com) - * - * Shared with ARM platforms, Jamie Iles, Picochip 2011 - * - * 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. - * - * Support for the Synopsys DesignWare APB Timers. - */ -#ifndef __DW_APB_TIMER_H__ -#define __DW_APB_TIMER_H__ - -#include -#include -#include - -#define APBTMRS_REG_SIZE 0x14 - -struct dw_apb_timer { - void __iomem *base; - unsigned long freq; - int irq; -}; - -struct dw_apb_clock_event_device { - struct clock_event_device ced; - struct dw_apb_timer timer; - struct irqaction irqaction; - void (*eoi)(struct dw_apb_timer *); -}; - -struct dw_apb_clocksource { - struct dw_apb_timer timer; - struct clocksource cs; -}; - -void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced); -void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced); -void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced); -void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced); - -struct dw_apb_clock_event_device * -dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, - void __iomem *base, int irq, unsigned long freq); -struct dw_apb_clocksource * -dw_apb_clocksource_init(unsigned rating, char *name, void __iomem *base, - unsigned long freq); -void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs); -void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs); -cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs); -void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs); - -#endif /* __DW_APB_TIMER_H__ */ diff --git a/trunk/include/linux/ext3_fs.h b/trunk/include/linux/ext3_fs.h index 0c473fd79acb..5e06acf95d0f 100644 --- a/trunk/include/linux/ext3_fs.h +++ b/trunk/include/linux/ext3_fs.h @@ -877,7 +877,7 @@ extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, extern void ext3_htree_free_dir_info(struct dir_private_info *p); /* fsync.c */ -extern int ext3_sync_file(struct file *, loff_t, loff_t, int); +extern int ext3_sync_file(struct file *, int); /* hash.c */ extern int ext3fs_dirhash(const char *name, int len, struct diff --git a/trunk/include/linux/fb.h b/trunk/include/linux/fb.h index 1d6836c498dd..6a8274877171 100644 --- a/trunk/include/linux/fb.h +++ b/trunk/include/linux/fb.h @@ -1043,8 +1043,7 @@ extern void fb_deferred_io_open(struct fb_info *info, struct inode *inode, struct file *file); extern void fb_deferred_io_cleanup(struct fb_info *info); -extern int fb_deferred_io_fsync(struct file *file, loff_t start, - loff_t end, int datasync); +extern int fb_deferred_io_fsync(struct file *file, int datasync); static inline bool fb_be_math(struct fb_info *info) { diff --git a/trunk/include/linux/fs.h b/trunk/include/linux/fs.h index b224dc468a23..b5b979247863 100644 --- a/trunk/include/linux/fs.h +++ b/trunk/include/linux/fs.h @@ -32,9 +32,7 @@ #define SEEK_SET 0 /* seek relative to beginning of file */ #define SEEK_CUR 1 /* seek relative to current file position */ #define SEEK_END 2 /* seek relative to end of file */ -#define SEEK_DATA 3 /* seek to the next data */ -#define SEEK_HOLE 4 /* seek to the next hole */ -#define SEEK_MAX SEEK_HOLE +#define SEEK_MAX SEEK_END struct fstrim_range { __u64 start; @@ -65,7 +63,6 @@ struct inodes_stat_t { #define MAY_ACCESS 16 #define MAY_OPEN 32 #define MAY_CHDIR 64 -#define MAY_NOT_BLOCK 128 /* called from RCU mode, don't block */ /* * flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond @@ -395,9 +392,8 @@ struct inodes_stat_t { #include #include #include -#include -#include +#include #include struct export_operations; @@ -781,7 +777,7 @@ struct inode { struct timespec i_ctime; blkcnt_t i_blocks; unsigned short i_bytes; - atomic_t i_dio_count; + struct rw_semaphore i_alloc_sem; const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ struct file_lock *i_flock; struct address_space *i_mapping; @@ -1400,11 +1396,6 @@ struct super_block { struct list_head s_dentry_lru; /* unused dentry lru */ int s_nr_dentry_unused; /* # of dentry on lru */ - /* s_inode_lru_lock protects s_inode_lru and s_nr_inodes_unused */ - spinlock_t s_inode_lru_lock ____cacheline_aligned_in_smp; - struct list_head s_inode_lru; /* unused inode lru */ - int s_nr_inodes_unused; /* # of inodes on lru */ - struct block_device *s_bdev; struct backing_dev_info *s_bdi; struct mtd_info *s_mtd; @@ -1447,14 +1438,8 @@ struct super_block { * Saved pool identifier for cleancache (-1 means none) */ int cleancache_poolid; - - struct shrinker s_shrink; /* per-sb shrinker handle */ }; -/* superblock cache pruning functions */ -extern void prune_icache_sb(struct super_block *sb, int nr_to_scan); -extern void prune_dcache_sb(struct super_block *sb, int nr_to_scan); - extern struct timespec current_fs_time(struct super_block *sb); /* @@ -1505,6 +1490,7 @@ extern void dentry_unhash(struct dentry *dentry); /* * VFS file helper functions. */ +extern int file_permission(struct file *, int); extern void inode_init_owner(struct inode *inode, const struct inode *dir, mode_t mode); /* @@ -1552,6 +1538,11 @@ struct block_device_operations; #define HAVE_COMPAT_IOCTL 1 #define HAVE_UNLOCKED_IOCTL 1 +/* + * NOTE: + * all file operations except setlease can be called without + * the big kernel lock held in all filesystems. + */ struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); @@ -1567,7 +1558,7 @@ struct file_operations { int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); - int (*fsync) (struct file *, loff_t, loff_t, int datasync); + int (*fsync) (struct file *, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); @@ -1582,11 +1573,13 @@ struct file_operations { loff_t len); }; +#define IPERM_FLAG_RCU 0x0001 + struct inode_operations { struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); void * (*follow_link) (struct dentry *, struct nameidata *); - int (*permission) (struct inode *, int); - int (*check_acl)(struct inode *, int); + int (*permission) (struct inode *, int, unsigned int); + int (*check_acl)(struct inode *, int, unsigned int); int (*readlink) (struct dentry *, char __user *,int); void (*put_link) (struct dentry *, struct nameidata *, void *); @@ -1652,8 +1645,6 @@ struct super_operations { ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); #endif int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t); - int (*nr_cached_objects)(struct super_block *); - void (*free_cached_objects)(struct super_block *, int); }; /* @@ -1702,10 +1693,6 @@ struct super_operations { * set during data writeback, and cleared with a wakeup * on the bit address once it is done. * - * I_REFERENCED Marks the inode as recently references on the LRU list. - * - * I_DIO_WAKEUP Never set. Only used as a key for wait_on_bit(). - * * Q: What is the difference between I_WILL_FREE and I_FREEING? */ #define I_DIRTY_SYNC (1 << 0) @@ -1719,8 +1706,6 @@ struct super_operations { #define __I_SYNC 7 #define I_SYNC (1 << __I_SYNC) #define I_REFERENCED (1 << 8) -#define __I_DIO_WAKEUP 9 -#define I_DIO_WAKEUP (1 << I_DIO_WAKEUP) #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES) @@ -1831,6 +1816,7 @@ struct file_system_type { struct lock_class_key i_lock_key; struct lock_class_key i_mutex_key; struct lock_class_key i_mutex_dir_key; + struct lock_class_key i_alloc_sem_key; }; extern struct dentry *mount_ns(struct file_system_type *fs_type, int flags, @@ -1851,8 +1837,6 @@ void kill_litter_super(struct super_block *sb); void deactivate_super(struct super_block *sb); void deactivate_locked_super(struct super_block *sb); int set_anon_super(struct super_block *s, void *data); -int get_anon_bdev(dev_t *); -void free_anon_bdev(dev_t); struct super_block *sget(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *), @@ -2204,38 +2188,16 @@ extern sector_t bmap(struct inode *, sector_t); #endif extern int notify_change(struct dentry *, struct iattr *); extern int inode_permission(struct inode *, int); -extern int generic_permission(struct inode *, int); +extern int generic_permission(struct inode *, int, unsigned int, + int (*check_acl)(struct inode *, int, unsigned int)); static inline bool execute_ok(struct inode *inode) { return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode); } -/* - * get_write_access() gets write permission for a file. - * put_write_access() releases this write permission. - * This is used for regular files. - * We cannot support write (and maybe mmap read-write shared) accesses and - * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode - * can have the following values: - * 0: no writers, no VM_DENYWRITE mappings - * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist - * > 0: (i_writecount) users are writing to the file. - * - * Normally we operate on that counter with atomic_{inc,dec} and it's safe - * except for the cases where we don't hold i_writecount yet. Then we need to - * use {get,deny}_write_access() - these functions check the sign and refuse - * to do the change if sign is wrong. - */ -static inline int get_write_access(struct inode *inode) -{ - return atomic_inc_unless_negative(&inode->i_writecount) ? 0 : -ETXTBSY; -} -static inline int deny_write_access(struct file *file) -{ - struct inode *inode = file->f_path.dentry->d_inode; - return atomic_dec_unless_positive(&inode->i_writecount) ? 0 : -ETXTBSY; -} +extern int get_write_access(struct inode *); +extern int deny_write_access(struct file *); static inline void put_write_access(struct inode * inode) { atomic_dec(&inode->i_writecount); @@ -2355,8 +2317,7 @@ extern int generic_segment_checks(const struct iovec *iov, /* fs/block_dev.c */ extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); -extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, - int datasync); +extern int blkdev_fsync(struct file *filp, int datasync); /* fs/splice.c */ extern ssize_t generic_file_splice_read(struct file *, loff_t *, @@ -2407,8 +2368,6 @@ enum { }; void dio_end_io(struct bio *bio, int error); -void inode_dio_wait(struct inode *inode); -void inode_dio_done(struct inode *inode); ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, struct block_device *bdev, const struct iovec *iov, loff_t offset, @@ -2416,17 +2375,14 @@ ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, dio_submit_t submit_io, int flags); static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb, - struct inode *inode, const struct iovec *iov, loff_t offset, - unsigned long nr_segs, get_block_t get_block) + struct inode *inode, struct block_device *bdev, const struct iovec *iov, + loff_t offset, unsigned long nr_segs, get_block_t get_block, + dio_iodone_t end_io) { - return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, - offset, nr_segs, get_block, NULL, NULL, + return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, + nr_segs, get_block, end_io, NULL, DIO_LOCKING | DIO_SKIP_HOLES); } -#else -static inline void inode_dio_wait(struct inode *inode) -{ -} #endif extern const struct file_operations generic_ro_fops; @@ -2476,8 +2432,6 @@ extern struct super_block *get_active_super(struct block_device *bdev); extern struct super_block *user_get_super(dev_t); extern void drop_super(struct super_block *sb); extern void iterate_supers(void (*)(struct super_block *, void *), void *); -extern void iterate_supers_type(struct file_system_type *, - void (*)(struct super_block *, void *), void *); extern int dcache_dir_open(struct inode *, struct file *); extern int dcache_dir_close(struct inode *, struct file *); @@ -2490,7 +2444,7 @@ extern int simple_link(struct dentry *, struct inode *, struct dentry *); extern int simple_unlink(struct inode *, struct dentry *); extern int simple_rmdir(struct inode *, struct dentry *); extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); -extern int noop_fsync(struct file *, loff_t, loff_t, int); +extern int noop_fsync(struct file *, int); extern int simple_empty(struct dentry *); extern int simple_readpage(struct file *file, struct page *page); extern int simple_write_begin(struct file *file, struct address_space *mapping, @@ -2515,7 +2469,7 @@ extern ssize_t simple_read_from_buffer(void __user *to, size_t count, extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos, const void __user *from, size_t count); -extern int generic_file_fsync(struct file *, loff_t, loff_t, int); +extern int generic_file_fsync(struct file *, int); extern int generic_check_addressable(unsigned, u64); diff --git a/trunk/include/linux/generic_acl.h b/trunk/include/linux/generic_acl.h index 574bea4013b6..0437e377b555 100644 --- a/trunk/include/linux/generic_acl.h +++ b/trunk/include/linux/generic_acl.h @@ -10,6 +10,6 @@ extern const struct xattr_handler generic_acl_default_handler; int generic_acl_init(struct inode *, struct inode *); int generic_acl_chmod(struct inode *); -int generic_check_acl(struct inode *inode, int mask); +int generic_check_acl(struct inode *inode, int mask, unsigned int flags); #endif /* LINUX_GENERIC_ACL_H */ diff --git a/trunk/include/linux/irq.h b/trunk/include/linux/irq.h index 5f695041090c..baa397eb9c33 100644 --- a/trunk/include/linux/irq.h +++ b/trunk/include/linux/irq.h @@ -96,6 +96,11 @@ enum { #define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING) +static inline __deprecated bool CHECK_IRQ_PER_CPU(unsigned int status) +{ + return status & IRQ_PER_CPU; +} + /* * Return value for chip->irq_set_affinity() * diff --git a/trunk/include/linux/iscsi_boot_sysfs.h b/trunk/include/linux/iscsi_boot_sysfs.h index f0a2f8b0aa13..f1e6c184f14f 100644 --- a/trunk/include/linux/iscsi_boot_sysfs.h +++ b/trunk/include/linux/iscsi_boot_sysfs.h @@ -92,13 +92,6 @@ struct iscsi_boot_kobj { * properties. */ mode_t (*is_visible) (void *data, int type); - - /* - * Driver specific release function. - * - * The function should free the data passed in. - */ - void (*release) (void *data); }; struct iscsi_boot_kset { @@ -110,21 +103,18 @@ struct iscsi_boot_kobj * iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)); + mode_t (*is_visible) (void *data, int type)); struct iscsi_boot_kobj * iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)); + mode_t (*is_visible) (void *data, int type)); struct iscsi_boot_kobj * iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), - void (*release) (void *data)); + mode_t (*is_visible) (void *data, int type)); struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name); struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno); diff --git a/trunk/include/linux/mm.h b/trunk/include/linux/mm.h index 8a45ad22a170..c70a326b8f26 100644 --- a/trunk/include/linux/mm.h +++ b/trunk/include/linux/mm.h @@ -15,7 +15,6 @@ #include #include #include -#include struct mempolicy; struct anon_vma; @@ -1122,6 +1121,44 @@ static inline void sync_mm_rss(struct task_struct *task, struct mm_struct *mm) } #endif +/* + * This struct is used to pass information from page reclaim to the shrinkers. + * We consolidate the values for easier extention later. + */ +struct shrink_control { + gfp_t gfp_mask; + + /* How many slab objects shrinker() should scan and try to reclaim */ + unsigned long nr_to_scan; +}; + +/* + * A callback you can register to apply pressure to ageable caches. + * + * 'sc' is passed shrink_control which includes a count 'nr_to_scan' + * and a 'gfpmask'. It should look through the least-recently-used + * 'nr_to_scan' entries and attempt to free them up. It should return + * the number of objects which remain in the cache. If it returns -1, it means + * it cannot do any scanning at this time (eg. there is a risk of deadlock). + * + * The 'gfpmask' refers to the allocation we are currently trying to + * fulfil. + * + * Note that 'shrink' will be passed nr_to_scan == 0 when the VM is + * querying the cache size, so a fastpath for that case is appropriate. + */ +struct shrinker { + int (*shrink)(struct shrinker *, struct shrink_control *sc); + int seeks; /* seeks to recreate an obj */ + + /* These are for internal use */ + struct list_head list; + long nr; /* objs pending delete */ +}; +#define DEFAULT_SEEKS 2 /* A good number if you don't know better. */ +extern void register_shrinker(struct shrinker *); +extern void unregister_shrinker(struct shrinker *); + int vma_wants_writenotify(struct vm_area_struct *vma); extern pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr, diff --git a/trunk/include/linux/mnt_namespace.h b/trunk/include/linux/mnt_namespace.h index 29304855652d..0b89efc6f215 100644 --- a/trunk/include/linux/mnt_namespace.h +++ b/trunk/include/linux/mnt_namespace.h @@ -18,6 +18,7 @@ struct proc_mounts { struct seq_file m; /* must be the first element */ struct mnt_namespace *ns; struct path root; + int event; }; struct fs_struct; diff --git a/trunk/include/linux/namei.h b/trunk/include/linux/namei.h index 76fe2c62ae71..eba45ea10298 100644 --- a/trunk/include/linux/namei.h +++ b/trunk/include/linux/namei.h @@ -48,6 +48,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; */ #define LOOKUP_FOLLOW 0x0001 #define LOOKUP_DIRECTORY 0x0002 +#define LOOKUP_CONTINUE 0x0004 #define LOOKUP_PARENT 0x0010 #define LOOKUP_REVAL 0x0020 @@ -74,11 +75,9 @@ extern int user_path_at(int, const char __user *, unsigned, struct path *); extern int kern_path(const char *, unsigned, struct path *); -extern struct dentry *kern_path_create(int, const char *, struct path *, int); -extern struct dentry *user_path_create(int, const char __user *, struct path *, int); extern int kern_path_parent(const char *, struct nameidata *); extern int vfs_path_lookup(struct dentry *, struct vfsmount *, - const char *, unsigned int, struct path *); + const char *, unsigned int, struct nameidata *); extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, int (*open)(struct inode *, struct file *)); diff --git a/trunk/include/linux/nfs_fs.h b/trunk/include/linux/nfs_fs.h index 8b579beb6358..1b93b9c60e55 100644 --- a/trunk/include/linux/nfs_fs.h +++ b/trunk/include/linux/nfs_fs.h @@ -85,7 +85,7 @@ struct nfs_lock_context { struct nfs4_state; struct nfs_open_context { struct nfs_lock_context lock_context; - struct dentry *dentry; + struct path path; struct rpc_cred *cred; struct nfs4_state *state; fmode_t mode; @@ -360,7 +360,7 @@ extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr); extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr); extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); -extern int nfs_permission(struct inode *, int); +extern int nfs_permission(struct inode *, int, unsigned int); extern int nfs_open(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *); extern int nfs_attribute_timeout(struct inode *inode); @@ -372,7 +372,7 @@ extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); extern void put_nfs_open_context(struct nfs_open_context *ctx); extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); -extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred, fmode_t f_mode); +extern struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode); extern void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx); extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx); extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx); diff --git a/trunk/include/linux/nsproxy.h b/trunk/include/linux/nsproxy.h index cc37a55ad004..50d20aba57d3 100644 --- a/trunk/include/linux/nsproxy.h +++ b/trunk/include/linux/nsproxy.h @@ -68,7 +68,6 @@ void switch_task_namespaces(struct task_struct *tsk, struct nsproxy *new); void free_nsproxy(struct nsproxy *ns); int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **, struct fs_struct *); -int __init nsproxy_cache_init(void); static inline void put_nsproxy(struct nsproxy *ns) { diff --git a/trunk/include/linux/pci_ids.h b/trunk/include/linux/pci_ids.h index 74173c585afa..057093043067 100644 --- a/trunk/include/linux/pci_ids.h +++ b/trunk/include/linux/pci_ids.h @@ -1308,7 +1308,6 @@ #define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041 #define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042 #define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043 -#define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062 #define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000 #define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */ diff --git a/trunk/include/linux/regmap.h b/trunk/include/linux/regmap.h deleted file mode 100644 index 60a65cd7e1a0..000000000000 --- a/trunk/include/linux/regmap.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef __LINUX_REGMAP_H -#define __LINUX_REGMAP_H - -/* - * Register map access API - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * 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 -#include -#include - -struct i2c_client; -struct spi_device; - -struct regmap_config { - int reg_bits; - int val_bits; -}; - -typedef int (*regmap_hw_write)(struct device *dev, const void *data, - size_t count); -typedef int (*regmap_hw_gather_write)(struct device *dev, - const void *reg, size_t reg_len, - const void *val, size_t val_len); -typedef int (*regmap_hw_read)(struct device *dev, - const void *reg_buf, size_t reg_size, - void *val_buf, size_t val_size); - -/** - * Description of a hardware bus for the register map infrastructure. - * - * @list: Internal use. - * @type: Bus type, used to identify bus to be used for a device. - * @write: Write operation. - * @gather_write: Write operation with split register/value, return -ENOTSUPP - * if not implemented on a given device. - * @read: Read operation. Data is returned in the buffer used to transmit - * data. - * @owner: Module with the bus implementation, used to pin the implementation - * in memory. - * @read_flag_mask: Mask to be set in the top byte of the register when doing - * a read. - */ -struct regmap_bus { - struct list_head list; - struct bus_type *type; - regmap_hw_write write; - regmap_hw_gather_write gather_write; - regmap_hw_read read; - struct module *owner; - u8 read_flag_mask; -}; - -struct regmap *regmap_init(struct device *dev, - const struct regmap_bus *bus, - const struct regmap_config *config); -struct regmap *regmap_init_i2c(struct i2c_client *i2c, - const struct regmap_config *config); -struct regmap *regmap_init_spi(struct spi_device *dev, - const struct regmap_config *config); - -void regmap_exit(struct regmap *map); -int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); -int regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len); -int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); -int regmap_raw_read(struct regmap *map, unsigned int reg, - void *val, size_t val_len); -int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, - size_t val_count); -int regmap_update_bits(struct regmap *map, unsigned int reg, - unsigned int mask, unsigned int val); - -#endif diff --git a/trunk/include/linux/reiserfs_xattr.h b/trunk/include/linux/reiserfs_xattr.h index 57958c0e1d38..6deef5dc95fb 100644 --- a/trunk/include/linux/reiserfs_xattr.h +++ b/trunk/include/linux/reiserfs_xattr.h @@ -41,11 +41,10 @@ int reiserfs_xattr_init(struct super_block *sb, int mount_flags); int reiserfs_lookup_privroot(struct super_block *sb); int reiserfs_delete_xattrs(struct inode *inode); int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs); -int reiserfs_permission(struct inode *inode, int mask); +int reiserfs_permission(struct inode *inode, int mask, unsigned int flags); #ifdef CONFIG_REISERFS_FS_XATTR #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir) -int reiserfs_check_acl(struct inode *inode, int mask); ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size); int reiserfs_setxattr(struct dentry *dentry, const char *name, @@ -123,7 +122,6 @@ static inline void reiserfs_init_xattr_rwsem(struct inode *inode) #define reiserfs_setxattr NULL #define reiserfs_listxattr NULL #define reiserfs_removexattr NULL -#define reiserfs_check_acl NULL static inline void reiserfs_init_xattr_rwsem(struct inode *inode) { diff --git a/trunk/include/linux/rwsem.h b/trunk/include/linux/rwsem.h index 77950dfa0a9e..a8afe9cd000c 100644 --- a/trunk/include/linux/rwsem.h +++ b/trunk/include/linux/rwsem.h @@ -124,9 +124,19 @@ extern void downgrade_write(struct rw_semaphore *sem); */ extern void down_read_nested(struct rw_semaphore *sem, int subclass); extern void down_write_nested(struct rw_semaphore *sem, int subclass); +/* + * Take/release a lock when not the owner will release it. + * + * [ This API should be avoided as much as possible - the + * proper abstraction for this case is completions. ] + */ +extern void down_read_non_owner(struct rw_semaphore *sem); +extern void up_read_non_owner(struct rw_semaphore *sem); #else # define down_read_nested(sem, subclass) down_read(sem) # define down_write_nested(sem, subclass) down_write(sem) +# define down_read_non_owner(sem) down_read(sem) +# define up_read_non_owner(sem) up_read(sem) #endif #endif /* _LINUX_RWSEM_H */ diff --git a/trunk/include/linux/security.h b/trunk/include/linux/security.h index ebd2a53a3d07..8ce59ef3e5af 100644 --- a/trunk/include/linux/security.h +++ b/trunk/include/linux/security.h @@ -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, @@ -1720,6 +1720,7 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, int security_inode_readlink(struct dentry *dentry); int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd); int security_inode_permission(struct inode *inode, int mask); +int security_inode_exec_permission(struct inode *inode, unsigned int flags); int security_inode_setattr(struct dentry *dentry, struct iattr *attr); int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry); int security_inode_setxattr(struct dentry *dentry, const char *name, @@ -2112,6 +2113,12 @@ static inline int security_inode_permission(struct inode *inode, int mask) return 0; } +static inline int security_inode_exec_permission(struct inode *inode, + unsigned int flags) +{ + return 0; +} + static inline int security_inode_setattr(struct dentry *dentry, struct iattr *attr) { diff --git a/trunk/include/linux/seq_file.h b/trunk/include/linux/seq_file.h index be720cd2038d..03c0232b4169 100644 --- a/trunk/include/linux/seq_file.h +++ b/trunk/include/linux/seq_file.h @@ -23,7 +23,6 @@ struct seq_file { u64 version; struct mutex lock; const struct seq_operations *op; - int poll_event; void *private; }; diff --git a/trunk/include/linux/shrinker.h b/trunk/include/linux/shrinker.h deleted file mode 100644 index 790651b4e5ba..000000000000 --- a/trunk/include/linux/shrinker.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _LINUX_SHRINKER_H -#define _LINUX_SHRINKER_H - -/* - * This struct is used to pass information from page reclaim to the shrinkers. - * We consolidate the values for easier extention later. - */ -struct shrink_control { - gfp_t gfp_mask; - - /* How many slab objects shrinker() should scan and try to reclaim */ - unsigned long nr_to_scan; -}; - -/* - * A callback you can register to apply pressure to ageable caches. - * - * 'sc' is passed shrink_control which includes a count 'nr_to_scan' - * and a 'gfpmask'. It should look through the least-recently-used - * 'nr_to_scan' entries and attempt to free them up. It should return - * the number of objects which remain in the cache. If it returns -1, it means - * it cannot do any scanning at this time (eg. there is a risk of deadlock). - * - * The 'gfpmask' refers to the allocation we are currently trying to - * fulfil. - * - * Note that 'shrink' will be passed nr_to_scan == 0 when the VM is - * querying the cache size, so a fastpath for that case is appropriate. - */ -struct shrinker { - int (*shrink)(struct shrinker *, struct shrink_control *sc); - int seeks; /* seeks to recreate an obj */ - long batch; /* reclaim batch size, 0 = default */ - - /* These are for internal use */ - struct list_head list; - long nr; /* objs pending delete */ -}; -#define DEFAULT_SEEKS 2 /* A good number if you don't know better. */ -extern void register_shrinker(struct shrinker *); -extern void unregister_shrinker(struct shrinker *); -#endif diff --git a/trunk/include/net/9p/9p.h b/trunk/include/net/9p/9p.h index 342dcf13d039..008711e8e78f 100644 --- a/trunk/include/net/9p/9p.h +++ b/trunk/include/net/9p/9p.h @@ -40,7 +40,6 @@ * @P9_DEBUG_FID: fid allocation/deallocation tracking * @P9_DEBUG_PKT: packet marshalling/unmarshalling * @P9_DEBUG_FSC: FS-cache tracing - * @P9_DEBUG_VPKT: Verbose packet debugging (full packet dump) * * These flags are passed at mount time to turn on various levels of * verbosity and tracing which will be output to the system logs. @@ -58,7 +57,6 @@ enum p9_debug_flags { P9_DEBUG_FID = (1<<9), P9_DEBUG_PKT = (1<<10), P9_DEBUG_FSC = (1<<11), - P9_DEBUG_VPKT = (1<<12), }; #ifdef CONFIG_NET_9P_DEBUG @@ -76,14 +74,10 @@ do { \ } \ } while (0) -#define P9_DUMP_PKT(way, pdu) p9pdu_dump(way, pdu) - #else #define P9_DPRINTK(level, format, arg...) do { } while (0) -#define P9_DUMP_PKT(way, pdu) do { } while (0) #endif - #define P9_EPRINTK(level, format, arg...) \ do { \ printk(level "9p: %s (%d): " \ @@ -181,10 +175,6 @@ enum p9_msg_t { P9_RLINK, P9_TMKDIR = 72, P9_RMKDIR, - P9_TRENAMEAT = 74, - P9_RRENAMEAT, - P9_TUNLINKAT = 76, - P9_RUNLINKAT, P9_TVERSION = 100, P9_RVERSION, P9_TAUTH = 102, @@ -330,6 +320,21 @@ enum p9_qid_t { /* Room for readdir header */ #define P9_READDIRHDRSZ 24 +/** + * struct p9_str - length prefixed string type + * @len: length of the string + * @str: the string + * + * The protocol uses length prefixed strings for all + * string data, so we replicate that for our internal + * string members. + */ + +struct p9_str { + u16 len; + char *str; +}; + /** * struct p9_qid - file system entity information * @type: 8-bit type &p9_qid_t @@ -366,11 +371,11 @@ struct p9_qid { * @atime: Last access/read time * @mtime: Last modify/write time * @length: file length - * @name: last element of path (aka filename) - * @uid: owner name - * @gid: group owner - * @muid: last modifier - * @extension: area used to encode extended UNIX support + * @name: last element of path (aka filename) in type &p9_str + * @uid: owner name in type &p9_str + * @gid: group owner in type &p9_str + * @muid: last modifier in type &p9_str + * @extension: area used to encode extended UNIX support in type &p9_str * @n_uid: numeric user id of owner (part of 9p2000.u extension) * @n_gid: numeric group id (part of 9p2000.u extension) * @n_muid: numeric user id of laster modifier (part of 9p2000.u extension) @@ -507,6 +512,11 @@ struct p9_getlock { char *client_id; }; +/* Structures for Protocol Operations */ +struct p9_tstatfs { + u32 fid; +}; + struct p9_rstatfs { u32 type; u32 bsize; @@ -519,6 +529,159 @@ struct p9_rstatfs { u32 namelen; }; +struct p9_trename { + u32 fid; + u32 newdirfid; + struct p9_str name; +}; + +struct p9_rrename { +}; + +struct p9_tversion { + u32 msize; + struct p9_str version; +}; + +struct p9_rversion { + u32 msize; + struct p9_str version; +}; + +struct p9_tauth { + u32 afid; + struct p9_str uname; + struct p9_str aname; + u32 n_uname; /* 9P2000.u extensions */ +}; + +struct p9_rauth { + struct p9_qid qid; +}; + +struct p9_rerror { + struct p9_str error; + u32 errno; /* 9p2000.u extension */ +}; + +struct p9_tflush { + u16 oldtag; +}; + +struct p9_rflush { +}; + +struct p9_tattach { + u32 fid; + u32 afid; + struct p9_str uname; + struct p9_str aname; + u32 n_uname; /* 9P2000.u extensions */ +}; + +struct p9_rattach { + struct p9_qid qid; +}; + +struct p9_twalk { + u32 fid; + u32 newfid; + u16 nwname; + struct p9_str wnames[16]; +}; + +struct p9_rwalk { + u16 nwqid; + struct p9_qid wqids[16]; +}; + +struct p9_topen { + u32 fid; + u8 mode; +}; + +struct p9_ropen { + struct p9_qid qid; + u32 iounit; +}; + +struct p9_tcreate { + u32 fid; + struct p9_str name; + u32 perm; + u8 mode; + struct p9_str extension; +}; + +struct p9_rcreate { + struct p9_qid qid; + u32 iounit; +}; + +struct p9_tread { + u32 fid; + u64 offset; + u32 count; +}; + +struct p9_rread { + u32 count; + u8 *data; +}; + +struct p9_twrite { + u32 fid; + u64 offset; + u32 count; + u8 *data; +}; + +struct p9_rwrite { + u32 count; +}; + +struct p9_treaddir { + u32 fid; + u64 offset; + u32 count; +}; + +struct p9_rreaddir { + u32 count; + u8 *data; +}; + + +struct p9_tclunk { + u32 fid; +}; + +struct p9_rclunk { +}; + +struct p9_tremove { + u32 fid; +}; + +struct p9_rremove { +}; + +struct p9_tstat { + u32 fid; +}; + +struct p9_rstat { + struct p9_wstat stat; +}; + +struct p9_twstat { + u32 fid; + struct p9_wstat stat; +}; + +struct p9_rwstat { +}; + /** * struct p9_fcall - primary packet structure * @size: prefixed length of the structure diff --git a/trunk/include/net/9p/client.h b/trunk/include/net/9p/client.h index 55ce72ce9861..d26d5e98a173 100644 --- a/trunk/include/net/9p/client.h +++ b/trunk/include/net/9p/client.h @@ -36,9 +36,9 @@ */ enum p9_proto_versions{ - p9_proto_legacy, - p9_proto_2000u, - p9_proto_2000L, + p9_proto_legacy = 0, + p9_proto_2000u = 1, + p9_proto_2000L = 2, }; @@ -211,10 +211,7 @@ struct p9_dirent { }; int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb); -int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, - const char *name); -int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name, - struct p9_fid *newdirfid, const char *new_name); +int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name); struct p9_client *p9_client_create(const char *dev_name, char *options); void p9_client_destroy(struct p9_client *clnt); void p9_client_disconnect(struct p9_client *clnt); @@ -234,7 +231,6 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, int p9_client_clunk(struct p9_fid *fid); int p9_client_fsync(struct p9_fid *fid, int datasync); int p9_client_remove(struct p9_fid *fid); -int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags); int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count); int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, diff --git a/trunk/include/net/9p/transport.h b/trunk/include/net/9p/transport.h index 83531ebeee99..d8549fb9c742 100644 --- a/trunk/include/net/9p/transport.h +++ b/trunk/include/net/9p/transport.h @@ -67,7 +67,7 @@ struct p9_trans_module { void v9fs_register_trans(struct p9_trans_module *m); void v9fs_unregister_trans(struct p9_trans_module *m); -struct p9_trans_module *v9fs_get_trans_by_name(char *s); +struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name); struct p9_trans_module *v9fs_get_default_trans(void); void v9fs_put_trans(struct p9_trans_module *m); #endif /* NET_9P_TRANSPORT_H */ diff --git a/trunk/include/scsi/iscsi_proto.h b/trunk/include/scsi/iscsi_proto.h index ea68b3c56dbf..dd0a52cea95a 100644 --- a/trunk/include/scsi/iscsi_proto.h +++ b/trunk/include/scsi/iscsi_proto.h @@ -60,7 +60,7 @@ struct iscsi_hdr { uint8_t rsvd2[2]; uint8_t hlength; /* AHSs total length */ uint8_t dlength[3]; /* Data length */ - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag, opaque for target */ __be32 ttt; /* Target Task Tag */ __be32 statsn; @@ -122,7 +122,7 @@ struct iscsi_cmd { __be16 rsvd2; uint8_t hlength; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag */ __be32 data_length; __be32 cmdsn; @@ -198,7 +198,7 @@ struct iscsi_async { uint8_t rsvd2[2]; uint8_t rsvd3; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; uint8_t rsvd4[8]; __be32 statsn; __be32 exp_cmdsn; @@ -226,7 +226,7 @@ struct iscsi_nopout { __be16 rsvd2; uint8_t rsvd3; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag */ __be32 ttt; /* Target Transfer Tag */ __be32 cmdsn; @@ -241,7 +241,7 @@ struct iscsi_nopin { __be16 rsvd2; uint8_t rsvd3; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag */ __be32 ttt; /* Target Transfer Tag */ __be32 statsn; @@ -257,7 +257,7 @@ struct iscsi_tm { uint8_t rsvd1[2]; uint8_t hlength; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag */ itt_t rtt; /* Reference Task Tag */ __be32 cmdsn; @@ -315,7 +315,7 @@ struct iscsi_r2t_rsp { uint8_t rsvd2[2]; uint8_t hlength; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; /* Initiator Task Tag */ __be32 ttt; /* Target Transfer Tag */ __be32 statsn; @@ -333,7 +333,7 @@ struct iscsi_data { uint8_t rsvd2[2]; uint8_t rsvd3; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; __be32 ttt; __be32 rsvd4; @@ -353,7 +353,7 @@ struct iscsi_data_rsp { uint8_t cmd_status; uint8_t hlength; uint8_t dlength[3]; - struct scsi_lun lun; + uint8_t lun[8]; itt_t itt; __be32 ttt; __be32 statsn; diff --git a/trunk/include/scsi/libfc.h b/trunk/include/scsi/libfc.h index 7d96829b0c00..a3cbda4ddb5c 100644 --- a/trunk/include/scsi/libfc.h +++ b/trunk/include/scsi/libfc.h @@ -510,14 +510,6 @@ struct libfc_function_template { * STATUS: OPTIONAL */ int (*ddp_done)(struct fc_lport *, u16); - /* - * Sets up the DDP context for a given exchange id on the given - * scatterlist if LLD supports DDP for FCoE target. - * - * STATUS: OPTIONAL - */ - int (*ddp_target)(struct fc_lport *, u16, struct scatterlist *, - unsigned int); /* * Allow LLD to fill its own Link Error Status Block * diff --git a/trunk/include/scsi/libiscsi.h b/trunk/include/scsi/libiscsi.h index cedcff371c88..0f4367751b71 100644 --- a/trunk/include/scsi/libiscsi.h +++ b/trunk/include/scsi/libiscsi.h @@ -115,7 +115,7 @@ struct iscsi_task { /* copied values in case we need to send tmfs */ itt_t hdr_itt; __be32 cmdsn; - struct scsi_lun lun; + uint8_t lun[8]; int itt; /* this ITT */ diff --git a/trunk/include/sound/rawmidi.h b/trunk/include/sound/rawmidi.h index 6b14359d9fed..2480e7d10dcf 100644 --- a/trunk/include/sound/rawmidi.h +++ b/trunk/include/sound/rawmidi.h @@ -27,7 +27,6 @@ #include #include #include -#include #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) #include "seq_device.h" @@ -64,7 +63,6 @@ struct snd_rawmidi_global_ops { }; struct snd_rawmidi_runtime { - struct snd_rawmidi_substream *substream; unsigned int drain: 1, /* drain stage */ oss: 1; /* OSS compatible mode */ /* midi stream buffer */ @@ -81,7 +79,7 @@ struct snd_rawmidi_runtime { /* event handler (new bytes, input only) */ void (*event)(struct snd_rawmidi_substream *substream); /* defers calls to event [input] or ops->trigger [output] */ - struct work_struct event_work; + struct tasklet_struct tasklet; /* private data */ void *private_data; void (*private_free)(struct snd_rawmidi_substream *substream); diff --git a/trunk/include/sound/soc-dai.h b/trunk/include/sound/soc-dai.h index 5ad5f3a50c68..1bafe95dcf41 100644 --- a/trunk/include/sound/soc-dai.h +++ b/trunk/include/sound/soc-dai.h @@ -209,10 +209,6 @@ struct snd_soc_dai_driver { struct snd_soc_pcm_stream capture; struct snd_soc_pcm_stream playback; unsigned int symmetric_rates:1; - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; }; /* diff --git a/trunk/include/sound/soc-dapm.h b/trunk/include/sound/soc-dapm.h index e09505c5a490..c46e7d89561d 100644 --- a/trunk/include/sound/soc-dapm.h +++ b/trunk/include/sound/soc-dapm.h @@ -348,8 +348,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); -int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_route *route, int num); /* dapm events */ int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, @@ -431,7 +429,6 @@ struct snd_soc_dapm_path { /* status */ u32 connect:1; /* source and sink widgets are connected */ u32 walked:1; /* path has been walked */ - u32 weak:1; /* path ignored for power management */ int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); @@ -447,7 +444,6 @@ struct snd_soc_dapm_widget { char *name; /* widget name */ char *sname; /* stream name */ struct snd_soc_codec *codec; - struct snd_soc_platform *platform; struct list_head list; struct snd_soc_dapm_context *dapm; @@ -511,11 +507,10 @@ struct snd_soc_dapm_context { struct device *dev; /* from parent - for debug */ struct snd_soc_codec *codec; /* parent codec */ - struct snd_soc_platform *platform; /* parent platform */ struct snd_soc_card *card; /* parent card */ /* used during DAPM updates */ - enum snd_soc_bias_level target_bias_level; + int dev_power; struct list_head list; #ifdef CONFIG_DEBUG_FS diff --git a/trunk/include/sound/soc.h b/trunk/include/sound/soc.h index aa19f5a32ba8..3a4bd3a3c68d 100644 --- a/trunk/include/sound/soc.h +++ b/trunk/include/sound/soc.h @@ -202,16 +202,6 @@ #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \ SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) -/* - * Component probe and remove ordering levels for components with runtime - * dependencies. - */ -#define SND_SOC_COMP_ORDER_FIRST -2 -#define SND_SOC_COMP_ORDER_EARLY -1 -#define SND_SOC_COMP_ORDER_NORMAL 0 -#define SND_SOC_COMP_ORDER_LATE 1 -#define SND_SOC_COMP_ORDER_LAST 2 - /* * Bias levels * @@ -224,10 +214,10 @@ * @OFF: Power Off. No restrictions on transition times. */ enum snd_soc_bias_level { - SND_SOC_BIAS_OFF = 0, - SND_SOC_BIAS_STANDBY = 1, - SND_SOC_BIAS_PREPARE = 2, - SND_SOC_BIAS_ON = 3, + SND_SOC_BIAS_OFF, + SND_SOC_BIAS_STANDBY, + SND_SOC_BIAS_PREPARE, + SND_SOC_BIAS_ON, }; struct snd_jack; @@ -268,11 +258,6 @@ enum snd_soc_compress_type { SND_SOC_RBTREE_COMPRESSION }; -enum snd_soc_pcm_subclass { - SND_SOC_PCM_CLASS_PCM = 0, - SND_SOC_PCM_CLASS_BE = 1, -}; - int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, unsigned int freq, int dir); int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, @@ -312,10 +297,6 @@ 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); -int snd_soc_platform_read(struct snd_soc_platform *platform, - unsigned int reg); -int snd_soc_platform_write(struct snd_soc_platform *platform, - unsigned int reg, unsigned int val); /* Utility functions to get clock rates from various things */ int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); @@ -368,8 +349,6 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, const char *prefix); int snd_soc_add_controls(struct snd_soc_codec *codec, const struct snd_kcontrol_new *controls, int num_controls); -int snd_soc_add_platform_controls(struct snd_soc_platform *platform, - const struct snd_kcontrol_new *controls, int num_controls); int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, @@ -633,10 +612,6 @@ struct snd_soc_codec_driver { void (*seq_notifier)(struct snd_soc_dapm_context *, enum snd_soc_dapm_type, int); - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; }; /* SoC platform interface */ @@ -648,17 +623,10 @@ struct snd_soc_platform_driver { int (*resume)(struct snd_soc_dai *dai); /* pcm creation and destruction */ - int (*pcm_new)(struct snd_soc_pcm_runtime *); + int (*pcm_new)(struct snd_card *, struct snd_soc_dai *, + struct snd_pcm *); void (*pcm_free)(struct snd_pcm *); - /* 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; - int num_dapm_routes; - /* * For platform caused delay reporting. * Optional. @@ -668,14 +636,6 @@ struct snd_soc_platform_driver { /* platform stream ops */ struct snd_pcm_ops *ops; - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; - - /* platform IO - used for platform DAPM */ - unsigned int (*read)(struct snd_soc_platform *, unsigned int); - int (*write)(struct snd_soc_platform *, unsigned int, unsigned int); }; struct snd_soc_platform { @@ -690,8 +650,6 @@ struct snd_soc_platform { struct snd_soc_card *card; struct list_head list; struct list_head card_list; - - struct snd_soc_dapm_context dapm; }; struct snd_soc_dai_link { @@ -767,10 +725,8 @@ struct snd_soc_card { /* callbacks */ int (*set_bias_level)(struct snd_soc_card *, - struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); int (*set_bias_level_post)(struct snd_soc_card *, - struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); long pmdown_time; @@ -833,9 +789,6 @@ struct snd_soc_pcm_runtime { struct device dev; struct snd_soc_card *card; struct snd_soc_dai_link *dai_link; - struct mutex pcm_mutex; - enum snd_soc_pcm_subclass pcm_subclass; - struct snd_pcm_ops ops; unsigned int complete:1; unsigned int dev_registered:1; diff --git a/trunk/include/trace/events/asoc.h b/trunk/include/trace/events/asoc.h index 603f5a0f0365..ae973d2e27a1 100644 --- a/trunk/include/trace/events/asoc.h +++ b/trunk/include/trace/events/asoc.h @@ -9,7 +9,6 @@ struct snd_soc_jack; struct snd_soc_codec; -struct snd_soc_platform; struct snd_soc_card; struct snd_soc_dapm_widget; @@ -60,50 +59,6 @@ DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read, ); -DECLARE_EVENT_CLASS(snd_soc_preg, - - TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, - unsigned int val), - - TP_ARGS(platform, reg, val), - - TP_STRUCT__entry( - __string( name, platform->name ) - __field( int, id ) - __field( unsigned int, reg ) - __field( unsigned int, val ) - ), - - TP_fast_assign( - __assign_str(name, platform->name); - __entry->id = platform->id; - __entry->reg = reg; - __entry->val = val; - ), - - TP_printk("platform=%s.%d reg=%x val=%x", __get_str(name), - (int)__entry->id, (unsigned int)__entry->reg, - (unsigned int)__entry->val) -); - -DEFINE_EVENT(snd_soc_preg, snd_soc_preg_write, - - TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, - unsigned int val), - - TP_ARGS(platform, reg, val) - -); - -DEFINE_EVENT(snd_soc_preg, snd_soc_preg_read, - - TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, - unsigned int val), - - TP_ARGS(platform, reg, val) - -); - DECLARE_EVENT_CLASS(snd_soc_card, TP_PROTO(struct snd_soc_card *card, int val), diff --git a/trunk/include/trace/events/vmscan.h b/trunk/include/trace/events/vmscan.h index 36851f7f13da..b2c33bd955fa 100644 --- a/trunk/include/trace/events/vmscan.h +++ b/trunk/include/trace/events/vmscan.h @@ -179,83 +179,6 @@ DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_softlimit_re TP_ARGS(nr_reclaimed) ); -TRACE_EVENT(mm_shrink_slab_start, - TP_PROTO(struct shrinker *shr, struct shrink_control *sc, - long nr_objects_to_shrink, unsigned long pgs_scanned, - unsigned long lru_pgs, unsigned long cache_items, - unsigned long long delta, unsigned long total_scan), - - TP_ARGS(shr, sc, nr_objects_to_shrink, pgs_scanned, lru_pgs, - cache_items, delta, total_scan), - - TP_STRUCT__entry( - __field(struct shrinker *, shr) - __field(void *, shrink) - __field(long, nr_objects_to_shrink) - __field(gfp_t, gfp_flags) - __field(unsigned long, pgs_scanned) - __field(unsigned long, lru_pgs) - __field(unsigned long, cache_items) - __field(unsigned long long, delta) - __field(unsigned long, total_scan) - ), - - TP_fast_assign( - __entry->shr = shr; - __entry->shrink = shr->shrink; - __entry->nr_objects_to_shrink = nr_objects_to_shrink; - __entry->gfp_flags = sc->gfp_mask; - __entry->pgs_scanned = pgs_scanned; - __entry->lru_pgs = lru_pgs; - __entry->cache_items = cache_items; - __entry->delta = delta; - __entry->total_scan = total_scan; - ), - - TP_printk("%pF %p: objects to shrink %ld gfp_flags %s pgs_scanned %ld lru_pgs %ld cache items %ld delta %lld total_scan %ld", - __entry->shrink, - __entry->shr, - __entry->nr_objects_to_shrink, - show_gfp_flags(__entry->gfp_flags), - __entry->pgs_scanned, - __entry->lru_pgs, - __entry->cache_items, - __entry->delta, - __entry->total_scan) -); - -TRACE_EVENT(mm_shrink_slab_end, - TP_PROTO(struct shrinker *shr, int shrinker_retval, - long unused_scan_cnt, long new_scan_cnt), - - TP_ARGS(shr, shrinker_retval, unused_scan_cnt, new_scan_cnt), - - TP_STRUCT__entry( - __field(struct shrinker *, shr) - __field(void *, shrink) - __field(long, unused_scan) - __field(long, new_scan) - __field(int, retval) - __field(long, total_scan) - ), - - TP_fast_assign( - __entry->shr = shr; - __entry->shrink = shr->shrink; - __entry->unused_scan = unused_scan_cnt; - __entry->new_scan = new_scan_cnt; - __entry->retval = shrinker_retval; - __entry->total_scan = new_scan_cnt - unused_scan_cnt; - ), - - TP_printk("%pF %p: unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d", - __entry->shrink, - __entry->shr, - __entry->unused_scan, - __entry->new_scan, - __entry->total_scan, - __entry->retval) -); DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template, diff --git a/trunk/init/Kconfig b/trunk/init/Kconfig index e20aa3112240..27b8a7a43261 100644 --- a/trunk/init/Kconfig +++ b/trunk/init/Kconfig @@ -917,8 +917,6 @@ config ANON_INODES menuconfig EXPERT bool "Configure standard kernel features (expert users)" - # Unhide debug options, to make the on-by-default options visible - select DEBUG_KERNEL help This option allows certain base kernel options and settings to be disabled or tweaked. This is for specialized diff --git a/trunk/ipc/shm.c b/trunk/ipc/shm.c index 27884adb1a90..ab3385a21b27 100644 --- a/trunk/ipc/shm.c +++ b/trunk/ipc/shm.c @@ -277,13 +277,13 @@ static int shm_release(struct inode *ino, struct file *file) return 0; } -static int shm_fsync(struct file *file, loff_t start, loff_t end, int datasync) +static int shm_fsync(struct file *file, int datasync) { struct shm_file_data *sfd = shm_file_data(file); if (!sfd->file->f_op->fsync) return -EINVAL; - return sfd->file->f_op->fsync(sfd->file, start, end, datasync); + return sfd->file->f_op->fsync(sfd->file, datasync); } static unsigned long shm_get_unmapped_area(struct file *file, diff --git a/trunk/kernel/cgroup.c b/trunk/kernel/cgroup.c index e1c72c0f512b..2731d115d725 100644 --- a/trunk/kernel/cgroup.c +++ b/trunk/kernel/cgroup.c @@ -3542,8 +3542,7 @@ static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft, } /* the process need read permission on control file */ - /* AV: shouldn't we check that it's been opened for read instead? */ - ret = inode_permission(cfile->f_path.dentry->d_inode, MAY_READ); + ret = file_permission(cfile, MAY_READ); if (ret < 0) goto fail; diff --git a/trunk/kernel/fork.c b/trunk/kernel/fork.c index aeae5b11b62e..ca339c5c5819 100644 --- a/trunk/kernel/fork.c +++ b/trunk/kernel/fork.c @@ -1585,7 +1585,6 @@ void __init proc_caches_init(void) SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL); vm_area_cachep = KMEM_CACHE(vm_area_struct, SLAB_PANIC); mmap_init(); - nsproxy_cache_init(); } /* diff --git a/trunk/kernel/nsproxy.c b/trunk/kernel/nsproxy.c index 9aeab4b98c64..d6a00f3de15d 100644 --- a/trunk/kernel/nsproxy.c +++ b/trunk/kernel/nsproxy.c @@ -271,8 +271,10 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) return err; } -int __init nsproxy_cache_init(void) +static int __init nsproxy_cache_init(void) { nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC); return 0; } + +module_init(nsproxy_cache_init); diff --git a/trunk/kernel/rwsem.c b/trunk/kernel/rwsem.c index 176e5e56ffab..cae050b05f5e 100644 --- a/trunk/kernel/rwsem.c +++ b/trunk/kernel/rwsem.c @@ -117,6 +117,15 @@ void down_read_nested(struct rw_semaphore *sem, int subclass) EXPORT_SYMBOL(down_read_nested); +void down_read_non_owner(struct rw_semaphore *sem) +{ + might_sleep(); + + __down_read(sem); +} + +EXPORT_SYMBOL(down_read_non_owner); + void down_write_nested(struct rw_semaphore *sem, int subclass) { might_sleep(); @@ -127,6 +136,13 @@ void down_write_nested(struct rw_semaphore *sem, int subclass) EXPORT_SYMBOL(down_write_nested); +void up_read_non_owner(struct rw_semaphore *sem) +{ + __up_read(sem); +} + +EXPORT_SYMBOL(up_read_non_owner); + #endif diff --git a/trunk/mm/filemap.c b/trunk/mm/filemap.c index f820e600f1ad..a8251a8d3457 100644 --- a/trunk/mm/filemap.c +++ b/trunk/mm/filemap.c @@ -78,6 +78,9 @@ * ->i_mutex (generic_file_buffered_write) * ->mmap_sem (fault_in_pages_readable->do_page_fault) * + * ->i_mutex + * ->i_alloc_sem (various) + * * inode_wb_list_lock * sb_lock (fs/fs-writeback.c) * ->mapping->tree_lock (__sync_single_inode) diff --git a/trunk/mm/madvise.c b/trunk/mm/madvise.c index 74bf193eff04..2221491ed503 100644 --- a/trunk/mm/madvise.c +++ b/trunk/mm/madvise.c @@ -218,7 +218,7 @@ static long madvise_remove(struct vm_area_struct *vma, endoff = (loff_t)(end - vma->vm_start - 1) + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); - /* vmtruncate_range needs to take i_mutex */ + /* vmtruncate_range needs to take i_mutex and i_alloc_sem */ up_read(¤t->mm->mmap_sem); error = vmtruncate_range(mapping->host, offset, endoff); down_read(¤t->mm->mmap_sem); diff --git a/trunk/mm/rmap.c b/trunk/mm/rmap.c index 2540a39eea4a..23295f65ae43 100644 --- a/trunk/mm/rmap.c +++ b/trunk/mm/rmap.c @@ -21,6 +21,7 @@ * Lock ordering in mm: * * inode->i_mutex (while writing or truncating, not reading or faulting) + * inode->i_alloc_sem (vmtruncate_range) * mm->mmap_sem * page->flags PG_locked (lock_page) * mapping->i_mmap_mutex diff --git a/trunk/mm/swapfile.c b/trunk/mm/swapfile.c index 1b8c33907242..ff8dc1a18cb4 100644 --- a/trunk/mm/swapfile.c +++ b/trunk/mm/swapfile.c @@ -1681,14 +1681,19 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) } #ifdef CONFIG_PROC_FS +struct proc_swaps { + struct seq_file seq; + int event; +}; + static unsigned swaps_poll(struct file *file, poll_table *wait) { - struct seq_file *seq = file->private_data; + struct proc_swaps *s = file->private_data; poll_wait(file, &proc_poll_wait, wait); - if (seq->poll_event != atomic_read(&proc_poll_event)) { - seq->poll_event = atomic_read(&proc_poll_event); + if (s->event != atomic_read(&proc_poll_event)) { + s->event = atomic_read(&proc_poll_event); return POLLIN | POLLRDNORM | POLLERR | POLLPRI; } @@ -1778,16 +1783,24 @@ static const struct seq_operations swaps_op = { static int swaps_open(struct inode *inode, struct file *file) { - struct seq_file *seq; + struct proc_swaps *s; int ret; + s = kmalloc(sizeof(struct proc_swaps), GFP_KERNEL); + if (!s) + return -ENOMEM; + + file->private_data = s; + ret = seq_open(file, &swaps_op); - if (ret) + if (ret) { + kfree(s); return ret; + } - seq = file->private_data; - seq->poll_event = atomic_read(&proc_poll_event); - return 0; + s->seq.private = s; + s->event = atomic_read(&proc_poll_event); + return ret; } static const struct file_operations proc_swaps_operations = { diff --git a/trunk/mm/truncate.c b/trunk/mm/truncate.c index 003c6c685fc8..e13f22efaad7 100644 --- a/trunk/mm/truncate.c +++ b/trunk/mm/truncate.c @@ -622,11 +622,12 @@ int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end) return -ENOSYS; mutex_lock(&inode->i_mutex); - inode_dio_wait(inode); + down_write(&inode->i_alloc_sem); unmap_mapping_range(mapping, offset, (end - offset), 1); inode->i_op->truncate_range(inode, offset, end); /* unmap again to remove racily COWed private pages */ unmap_mapping_range(mapping, offset, (end - offset), 1); + up_write(&inode->i_alloc_sem); mutex_unlock(&inode->i_mutex); return 0; diff --git a/trunk/mm/vmscan.c b/trunk/mm/vmscan.c index febbc044e792..d036e59d302b 100644 --- a/trunk/mm/vmscan.c +++ b/trunk/mm/vmscan.c @@ -250,90 +250,49 @@ unsigned long shrink_slab(struct shrink_control *shrink, unsigned long long delta; unsigned long total_scan; unsigned long max_pass; - int shrink_ret = 0; - long nr; - long new_nr; - long batch_size = shrinker->batch ? shrinker->batch - : SHRINK_BATCH; - /* - * copy the current shrinker scan count into a local variable - * and zero it so that other concurrent shrinker invocations - * don't also do this scanning work. - */ - do { - nr = shrinker->nr; - } while (cmpxchg(&shrinker->nr, nr, 0) != nr); - - total_scan = nr; max_pass = do_shrinker_shrink(shrinker, shrink, 0); delta = (4 * nr_pages_scanned) / shrinker->seeks; delta *= max_pass; do_div(delta, lru_pages + 1); - total_scan += delta; - if (total_scan < 0) { + shrinker->nr += delta; + if (shrinker->nr < 0) { printk(KERN_ERR "shrink_slab: %pF negative objects to " "delete nr=%ld\n", - shrinker->shrink, total_scan); - total_scan = max_pass; + shrinker->shrink, shrinker->nr); + shrinker->nr = max_pass; } - /* - * We need to avoid excessive windup on filesystem shrinkers - * due to large numbers of GFP_NOFS allocations causing the - * shrinkers to return -1 all the time. This results in a large - * nr being built up so when a shrink that can do some work - * comes along it empties the entire cache due to nr >>> - * max_pass. This is bad for sustaining a working set in - * memory. - * - * Hence only allow the shrinker to scan the entire cache when - * a large delta change is calculated directly. - */ - if (delta < max_pass / 4) - total_scan = min(total_scan, max_pass / 2); - /* * Avoid risking looping forever due to too large nr value: * never try to free more than twice the estimate number of * freeable entries. */ - if (total_scan > max_pass * 2) - total_scan = max_pass * 2; + if (shrinker->nr > max_pass * 2) + shrinker->nr = max_pass * 2; - trace_mm_shrink_slab_start(shrinker, shrink, nr, - nr_pages_scanned, lru_pages, - max_pass, delta, total_scan); + total_scan = shrinker->nr; + shrinker->nr = 0; - while (total_scan >= batch_size) { + while (total_scan >= SHRINK_BATCH) { + long this_scan = SHRINK_BATCH; + int shrink_ret; int nr_before; nr_before = do_shrinker_shrink(shrinker, shrink, 0); shrink_ret = do_shrinker_shrink(shrinker, shrink, - batch_size); + this_scan); if (shrink_ret == -1) break; if (shrink_ret < nr_before) ret += nr_before - shrink_ret; - count_vm_events(SLABS_SCANNED, batch_size); - total_scan -= batch_size; + count_vm_events(SLABS_SCANNED, this_scan); + total_scan -= this_scan; cond_resched(); } - /* - * move the unused scan count back into the shrinker in a - * manner that handles concurrent updates. If we exhausted the - * scan, there is no need to do an update. - */ - do { - nr = shrinker->nr; - new_nr = total_scan + nr; - if (total_scan <= 0) - break; - } while (cmpxchg(&shrinker->nr, nr, new_nr) != nr); - - trace_mm_shrink_slab_end(shrinker, shrink_ret, nr, new_nr); + shrinker->nr += total_scan; } up_read(&shrinker_rwsem); out: diff --git a/trunk/net/9p/client.c b/trunk/net/9p/client.c index 0505a03c374c..9e3b0e640da1 100644 --- a/trunk/net/9p/client.c +++ b/trunk/net/9p/client.c @@ -72,22 +72,23 @@ inline int p9_is_proto_dotu(struct p9_client *clnt) EXPORT_SYMBOL(p9_is_proto_dotu); /* Interpret mount option for protocol version */ -static int get_protocol_version(char *s) +static int get_protocol_version(const substring_t *name) { int version = -EINVAL; - if (!strcmp(s, "9p2000")) { + if (!strncmp("9p2000", name->from, name->to-name->from)) { version = p9_proto_legacy; P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n"); - } else if (!strcmp(s, "9p2000.u")) { + } else if (!strncmp("9p2000.u", name->from, name->to-name->from)) { version = p9_proto_2000u; P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n"); - } else if (!strcmp(s, "9p2000.L")) { + } else if (!strncmp("9p2000.L", name->from, name->to-name->from)) { version = p9_proto_2000L; P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.L\n"); - } else - printk(KERN_INFO "9p: Unknown protocol version %s.\n", s); - + } else { + P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ", + name->from); + } return version; } @@ -105,7 +106,6 @@ static int parse_opts(char *opts, struct p9_client *clnt) char *p; substring_t args[MAX_OPT_ARGS]; int option; - char *s; int ret = 0; clnt->proto_version = p9_proto_2000u; @@ -141,41 +141,22 @@ static int parse_opts(char *opts, struct p9_client *clnt) clnt->msize = option; break; case Opt_trans: - s = match_strdup(&args[0]); - if (!s) { - ret = -ENOMEM; + clnt->trans_mod = v9fs_get_trans_by_name(&args[0]); + if(clnt->trans_mod == NULL) { P9_DPRINTK(P9_DEBUG_ERROR, - "problem allocating copy of trans arg\n"); - goto free_and_return; - } - clnt->trans_mod = v9fs_get_trans_by_name(s); - if (clnt->trans_mod == NULL) { - printk(KERN_INFO - "9p: Could not find " - "request transport: %s\n", s); + "Could not find request transport: %s\n", + (char *) &args[0]); ret = -EINVAL; - kfree(s); goto free_and_return; } - kfree(s); break; case Opt_legacy: clnt->proto_version = p9_proto_legacy; break; case Opt_version: - s = match_strdup(&args[0]); - if (!s) { - ret = -ENOMEM; - P9_DPRINTK(P9_DEBUG_ERROR, - "problem allocating copy of version arg\n"); + ret = get_protocol_version(&args[0]); + if (ret == -EINVAL) goto free_and_return; - } - ret = get_protocol_version(s); - if (ret == -EINVAL) { - kfree(s); - goto free_and_return; - } - kfree(s); clnt->proto_version = ret; break; default: @@ -299,8 +280,7 @@ struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag) * buffer to read the data into */ tag++; - if(tag >= c->max_tag) - return NULL; + BUG_ON(tag >= c->max_tag); row = tag / P9_ROW_MAXTAG; col = tag % P9_ROW_MAXTAG; @@ -769,7 +749,7 @@ static int p9_client_version(struct p9_client *c) err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version); if (err) { P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } @@ -841,8 +821,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) if (err) goto destroy_fidpool; - if (clnt->msize > clnt->trans_mod->maxsize) - clnt->msize = clnt->trans_mod->maxsize; + if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) + clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; err = p9_client_version(clnt); if (err) @@ -931,7 +911,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -991,7 +971,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto clunk_fid; } @@ -1058,7 +1038,7 @@ int p9_client_open(struct p9_fid *fid, int mode) err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1101,7 +1081,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1146,7 +1126,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1185,7 +1165,7 @@ int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1269,11 +1249,9 @@ int p9_client_clunk(struct p9_fid *fid) P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid); p9_free_req(clnt, req); -error: - /* - * Fid is not valid even after a failed clunk - */ p9_fid_destroy(fid); + +error: return err; } EXPORT_SYMBOL(p9_client_clunk); @@ -1303,29 +1281,6 @@ int p9_client_remove(struct p9_fid *fid) } EXPORT_SYMBOL(p9_client_remove); -int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags) -{ - int err = 0; - struct p9_req_t *req; - struct p9_client *clnt; - - P9_DPRINTK(P9_DEBUG_9P, ">>> TUNLINKAT fid %d %s %d\n", - dfid->fid, name, flags); - - clnt = dfid->clnt; - req = p9_client_rpc(clnt, P9_TUNLINKAT, "dsd", dfid->fid, name, flags); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto error; - } - P9_DPRINTK(P9_DEBUG_9P, "<<< RUNLINKAT fid %d %s\n", dfid->fid, name); - - p9_free_req(clnt, req); -error: - return err; -} -EXPORT_SYMBOL(p9_client_unlinkat); - int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count) @@ -1363,12 +1318,11 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); - P9_DUMP_PKT(1, req->rc); if (!req->tc->pbuf_size) { if (data) { @@ -1432,7 +1386,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1472,7 +1426,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid) err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -1523,7 +1477,7 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid, err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -1671,7 +1625,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb) &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail, &sb->files, &sb->ffree, &sb->fsid, &sb->namelen); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto error; } @@ -1689,8 +1643,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb) } EXPORT_SYMBOL(p9_client_statfs); -int p9_client_rename(struct p9_fid *fid, - struct p9_fid *newdirfid, const char *name) +int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name) { int err; struct p9_req_t *req; @@ -1717,36 +1670,6 @@ int p9_client_rename(struct p9_fid *fid, } EXPORT_SYMBOL(p9_client_rename); -int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name, - struct p9_fid *newdirfid, const char *new_name) -{ - int err; - struct p9_req_t *req; - struct p9_client *clnt; - - err = 0; - clnt = olddirfid->clnt; - - P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAMEAT olddirfid %d old name %s" - " newdirfid %d new name %s\n", olddirfid->fid, old_name, - newdirfid->fid, new_name); - - req = p9_client_rpc(clnt, P9_TRENAMEAT, "dsds", olddirfid->fid, - old_name, newdirfid->fid, new_name); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto error; - } - - P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAMEAT newdirfid %d new name %s\n", - newdirfid->fid, new_name); - - p9_free_req(clnt, req); -error: - return err; -} -EXPORT_SYMBOL(p9_client_renameat); - /* * An xattrwalk without @attr_name gives the fid for the lisxattr namespace */ @@ -1778,7 +1701,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid, } err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); p9_free_req(clnt, req); goto clunk_fid; } @@ -1857,7 +1780,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto free_and_error; } @@ -1894,7 +1817,7 @@ int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type, @@ -1925,7 +1848,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type, @@ -1960,7 +1883,7 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status) err = p9pdu_readf(req->rc, clnt->proto_version, "b", status); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status); @@ -1993,7 +1916,7 @@ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock) &glock->start, &glock->length, &glock->proc_id, &glock->client_id); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld " @@ -2021,7 +1944,7 @@ int p9_client_readlink(struct p9_fid *fid, char **target) err = p9pdu_readf(req->rc, clnt->proto_version, "s", target); if (err) { - P9_DUMP_PKT(1, req->rc); + p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target); diff --git a/trunk/net/9p/mod.c b/trunk/net/9p/mod.c index 2664d1292291..72c398275051 100644 --- a/trunk/net/9p/mod.c +++ b/trunk/net/9p/mod.c @@ -80,14 +80,14 @@ EXPORT_SYMBOL(v9fs_unregister_trans); * @name: string identifying transport * */ -struct p9_trans_module *v9fs_get_trans_by_name(char *s) +struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name) { struct p9_trans_module *t, *found = NULL; spin_lock(&v9fs_trans_lock); list_for_each_entry(t, &v9fs_trans_list, list) - if (strcmp(t->name, s) == 0 && + if (strncmp(t->name, name->from, name->to-name->from) == 0 && try_module_get(t->owner)) { found = t; break; diff --git a/trunk/net/9p/protocol.c b/trunk/net/9p/protocol.c index df58375ea6b3..a873277cb996 100644 --- a/trunk/net/9p/protocol.c +++ b/trunk/net/9p/protocol.c @@ -44,24 +44,30 @@ p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); void p9pdu_dump(int way, struct p9_fcall *pdu) { - int len = pdu->size; - - if ((p9_debug_level & P9_DEBUG_VPKT) != P9_DEBUG_VPKT) { - if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) { - if (len > 32) - len = 32; - } else { - /* shouldn't happen */ - return; - } + int i, n; + u8 *data = pdu->sdata; + int datalen = pdu->size; + char buf[255]; + int buflen = 255; + + i = n = 0; + if (datalen > (buflen-16)) + datalen = buflen-16; + while (i < datalen) { + n += scnprintf(buf + n, buflen - n, "%02x ", data[i]); + if (i%4 == 3) + n += scnprintf(buf + n, buflen - n, " "); + if (i%32 == 31) + n += scnprintf(buf + n, buflen - n, "\n"); + + i++; } + n += scnprintf(buf + n, buflen - n, "\n"); if (way) - print_hex_dump_bytes("[9P] ", DUMP_PREFIX_OFFSET, pdu->sdata, - len); + P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf); else - print_hex_dump_bytes("]9P[ ", DUMP_PREFIX_OFFSET, pdu->sdata, - len); + P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf); } #else void @@ -604,7 +610,7 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version) ret = p9pdu_readf(&fake_pdu, proto_version, "S", st); if (ret) { P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); - P9_DUMP_PKT(0, &fake_pdu); + p9pdu_dump(1, &fake_pdu); } return ret; @@ -626,7 +632,11 @@ int p9pdu_finalize(struct p9_fcall *pdu) err = p9pdu_writef(pdu, 0, "d", size); pdu->size = size; - P9_DUMP_PKT(0, pdu); +#ifdef CONFIG_NET_9P_DEBUG + if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) + p9pdu_dump(0, pdu); +#endif + P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size, pdu->id, pdu->tag); @@ -659,7 +669,7 @@ int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, &dirent->d_off, &dirent->d_type, &nameptr); if (ret) { P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret); - P9_DUMP_PKT(1, &fake_pdu); + p9pdu_dump(1, &fake_pdu); goto out; } diff --git a/trunk/net/9p/trans_virtio.c b/trunk/net/9p/trans_virtio.c index 175b5135bdcf..244e70742183 100644 --- a/trunk/net/9p/trans_virtio.c +++ b/trunk/net/9p/trans_virtio.c @@ -367,7 +367,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) in += inp; } else { in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, - req->rc->capacity); + client->msize); } err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); @@ -592,7 +592,7 @@ static struct p9_trans_module p9_virtio_trans = { .close = p9_virtio_close, .request = p9_virtio_request, .cancel = p9_virtio_cancel, - .maxsize = PAGE_SIZE*VIRTQUEUE_NUM, + .maxsize = PAGE_SIZE*16, .pref = P9_TRANS_PREF_PAYLOAD_SEP, .def = 0, .owner = THIS_MODULE, diff --git a/trunk/net/sunrpc/clnt.c b/trunk/net/sunrpc/clnt.c index c50818f0473b..7389b7da3a8d 100644 --- a/trunk/net/sunrpc/clnt.c +++ b/trunk/net/sunrpc/clnt.c @@ -97,7 +97,8 @@ static int rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) { static uint32_t clntid; - struct path path, dir; + struct nameidata nd; + struct path path; char name[15]; struct qstr q = { .name = name, @@ -112,7 +113,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) path.mnt = rpc_get_mount(); if (IS_ERR(path.mnt)) return PTR_ERR(path.mnt); - error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &dir); + error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &nd); if (error) goto err; @@ -120,7 +121,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); name[sizeof(name) - 1] = '\0'; q.hash = full_name_hash(q.name, q.len); - path.dentry = rpc_create_client_dir(dir.dentry, &q, clnt); + path.dentry = rpc_create_client_dir(nd.path.dentry, &q, clnt); if (!IS_ERR(path.dentry)) break; error = PTR_ERR(path.dentry); @@ -131,11 +132,11 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) goto err_path_put; } } - path_put(&dir); + path_put(&nd.path); clnt->cl_path = path; return 0; err_path_put: - path_put(&dir); + path_put(&nd.path); err: rpc_put_mount(); return error; diff --git a/trunk/net/unix/af_unix.c b/trunk/net/unix/af_unix.c index ec68e1c05b85..0722a25a3a33 100644 --- a/trunk/net/unix/af_unix.c +++ b/trunk/net/unix/af_unix.c @@ -808,9 +808,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; - char *sun_path = sunaddr->sun_path; struct dentry *dentry = NULL; - struct path path; + struct nameidata nd; int err; unsigned hash; struct unix_address *addr; @@ -846,44 +845,48 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) addr->hash = hash ^ sk->sk_type; atomic_set(&addr->refcnt, 1); - if (sun_path[0]) { + if (sunaddr->sun_path[0]) { unsigned int mode; err = 0; /* * Get the parent directory, calculate the hash for last * component. */ - dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); + err = kern_path_parent(sunaddr->sun_path, &nd); + if (err) + goto out_mknod_parent; + + dentry = lookup_create(&nd, 0); err = PTR_ERR(dentry); if (IS_ERR(dentry)) - goto out_mknod_parent; + goto out_mknod_unlock; /* * All right, let's create it. */ mode = S_IFSOCK | (SOCK_INODE(sock)->i_mode & ~current_umask()); - err = mnt_want_write(path.mnt); + err = mnt_want_write(nd.path.mnt); if (err) goto out_mknod_dput; - err = security_path_mknod(&path, dentry, mode, 0); + err = security_path_mknod(&nd.path, dentry, mode, 0); if (err) goto out_mknod_drop_write; - err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0); + err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0); out_mknod_drop_write: - mnt_drop_write(path.mnt); + mnt_drop_write(nd.path.mnt); if (err) goto out_mknod_dput; - mutex_unlock(&path.dentry->d_inode->i_mutex); - dput(path.dentry); - path.dentry = dentry; + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + dput(nd.path.dentry); + nd.path.dentry = dentry; addr->hash = UNIX_HASH_SIZE; } spin_lock(&unix_table_lock); - if (!sun_path[0]) { + if (!sunaddr->sun_path[0]) { err = -EADDRINUSE; if (__unix_find_socket_byname(net, sunaddr, addr_len, sk->sk_type, hash)) { @@ -894,8 +897,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) list = &unix_socket_table[addr->hash]; } else { list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; - u->dentry = path.dentry; - u->mnt = path.mnt; + u->dentry = nd.path.dentry; + u->mnt = nd.path.mnt; } err = 0; @@ -912,8 +915,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) out_mknod_dput: dput(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - path_put(&path); +out_mknod_unlock: + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); out_mknod_parent: if (err == -EEXIST) err = -EADDRINUSE; diff --git a/trunk/security/capability.c b/trunk/security/capability.c index 2984ea4f776f..bbb51156261b 100644 --- a/trunk/security/capability.c +++ b/trunk/security/capability.c @@ -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; } diff --git a/trunk/security/security.c b/trunk/security/security.c index 0e4fccfef12c..4ba6d4cc061f 100644 --- a/trunk/security/security.c +++ b/trunk/security/security.c @@ -518,7 +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; + return security_ops->inode_permission(inode, MAY_EXEC, flags); } int security_inode_setattr(struct dentry *dentry, struct iattr *attr) diff --git a/trunk/security/selinux/avc.c b/trunk/security/selinux/avc.c index dca1c22d9276..d515b2128a4e 100644 --- a/trunk/security/selinux/avc.c +++ b/trunk/security/selinux/avc.c @@ -527,7 +527,7 @@ int avc_audit(u32 ssid, u32 tsid, * happened a little later. */ if ((a->type == LSM_AUDIT_DATA_INODE) && - (flags & MAY_NOT_BLOCK)) + (flags & IPERM_FLAG_RCU)) return -ECHILD; a->selinux_audit_data.tclass = tclass; diff --git a/trunk/security/selinux/hooks.c b/trunk/security/selinux/hooks.c index 9f4c77dca35f..422515509f3d 100644 --- a/trunk/security/selinux/hooks.c +++ b/trunk/security/selinux/hooks.c @@ -2659,13 +2659,12 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na return dentry_has_perm(cred, 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; u32 perms; bool from_access; - unsigned flags = mask & MAY_NOT_BLOCK; from_access = mask & MAY_ACCESS; mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); diff --git a/trunk/security/smack/smack_lsm.c b/trunk/security/smack/smack_lsm.c index f375eb2e1957..9831a39c11f6 100644 --- a/trunk/security/smack/smack_lsm.c +++ b/trunk/security/smack/smack_lsm.c @@ -689,10 +689,9 @@ 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; - int no_block = mask & MAY_NOT_BLOCK; mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); /* @@ -702,7 +701,7 @@ static int smack_inode_permission(struct inode *inode, int mask) return 0; /* May be droppable after audit */ - if (no_block) + if (flags & IPERM_FLAG_RCU) return -ECHILD; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, inode); diff --git a/trunk/security/tomoyo/realpath.c b/trunk/security/tomoyo/realpath.c index 8d95e91c9fc4..d1e05b047715 100644 --- a/trunk/security/tomoyo/realpath.c +++ b/trunk/security/tomoyo/realpath.c @@ -103,7 +103,7 @@ char *tomoyo_realpath_from_path(struct path *path) if (!buf) break; /* Get better name for socket. */ - if (dentry->d_sb->s_magic == SOCKFS_MAGIC) { + if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) { struct inode *inode = dentry->d_inode; struct socket *sock = inode ? SOCKET_I(inode) : NULL; struct sock *sk = sock ? sock->sk : NULL; diff --git a/trunk/sound/core/rawmidi.c b/trunk/sound/core/rawmidi.c index 849a0ed95054..cbbed0db9e56 100644 --- a/trunk/sound/core/rawmidi.c +++ b/trunk/sound/core/rawmidi.c @@ -92,12 +92,16 @@ static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substre (!substream->append || runtime->avail >= count); } -static void snd_rawmidi_input_event_work(struct work_struct *work) +static void snd_rawmidi_input_event_tasklet(unsigned long data) { - struct snd_rawmidi_runtime *runtime = - container_of(work, struct snd_rawmidi_runtime, event_work); - if (runtime->event) - runtime->event(runtime->substream); + struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data; + substream->runtime->event(substream); +} + +static void snd_rawmidi_output_trigger_tasklet(unsigned long data) +{ + struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data; + substream->ops->trigger(substream, 1); } static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) @@ -106,10 +110,16 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL) return -ENOMEM; - runtime->substream = substream; spin_lock_init(&runtime->lock); init_waitqueue_head(&runtime->sleep); - INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work); + if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) + tasklet_init(&runtime->tasklet, + snd_rawmidi_input_event_tasklet, + (unsigned long)substream); + else + tasklet_init(&runtime->tasklet, + snd_rawmidi_output_trigger_tasklet, + (unsigned long)substream); runtime->event = NULL; runtime->buffer_size = PAGE_SIZE; runtime->avail_min = 1; @@ -140,7 +150,12 @@ static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *subs { if (!substream->opened) return; - substream->ops->trigger(substream, up); + if (up) { + tasklet_schedule(&substream->runtime->tasklet); + } else { + tasklet_kill(&substream->runtime->tasklet); + substream->ops->trigger(substream, 0); + } } static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) @@ -148,8 +163,8 @@ static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, i if (!substream->opened) return; substream->ops->trigger(substream, up); - if (!up) - cancel_work_sync(&substream->runtime->event_work); + if (!up && substream->runtime->event) + tasklet_kill(&substream->runtime->tasklet); } int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) @@ -626,10 +641,10 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, - GFP_KERNEL); + newbuf = kmalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; + kfree(runtime->buffer); runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; runtime->avail = runtime->buffer_size; @@ -653,10 +668,10 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, - GFP_KERNEL); + newbuf = kmalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; + kfree(runtime->buffer); runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; } @@ -911,7 +926,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, } if (result > 0) { if (runtime->event) - schedule_work(&runtime->event_work); + tasklet_schedule(&runtime->tasklet); else if (snd_rawmidi_ready(substream)) wake_up(&runtime->sleep); } diff --git a/trunk/sound/firewire/speakers.c b/trunk/sound/firewire/speakers.c index 3fc257da180c..5466de8527bd 100644 --- a/trunk/sound/firewire/speakers.c +++ b/trunk/sound/firewire/speakers.c @@ -171,7 +171,7 @@ static int fwspk_open(struct snd_pcm_substream *substream) err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, - 5000, UINT_MAX); + 5000, 8192000); if (err < 0) return err; diff --git a/trunk/sound/pci/ad1889.c b/trunk/sound/pci/ad1889.c index 201503673f25..d8f6fd65ebbb 100644 --- a/trunk/sound/pci/ad1889.c +++ b/trunk/sound/pci/ad1889.c @@ -944,7 +944,7 @@ snd_ad1889_create(struct snd_card *card, spin_lock_init(&chip->lock); /* only now can we call ad1889_free */ if (request_irq(pci->irq, snd_ad1889_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, card->driver, chip)) { printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq); snd_ad1889_free(chip); return -EBUSY; @@ -1055,7 +1055,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = { MODULE_DEVICE_TABLE(pci, snd_ad1889_ids); static struct pci_driver ad1889_pci_driver = { - .name = KBUILD_MODNAME, + .name = "AD1889 Audio", .id_table = snd_ad1889_ids, .probe = snd_ad1889_probe, .remove = __devexit_p(snd_ad1889_remove), diff --git a/trunk/sound/pci/ali5451/ali5451.c b/trunk/sound/pci/ali5451/ali5451.c index b444b74d9dcf..5c6e322a48f0 100644 --- a/trunk/sound/pci/ali5451/ali5451.c +++ b/trunk/sound/pci/ali5451/ali5451.c @@ -2090,7 +2090,7 @@ static int __devinit snd_ali_resources(struct snd_ali *codec) codec->port = pci_resource_start(codec->pci, 0); if (request_irq(codec->pci->irq, snd_ali_card_interrupt, - IRQF_SHARED, KBUILD_MODNAME, codec)) { + IRQF_SHARED, "ALI 5451", codec)) { snd_printk(KERN_ERR "Unable to request irq.\n"); return -EBUSY; } @@ -2295,7 +2295,7 @@ static void __devexit snd_ali_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ALI 5451", .id_table = snd_ali_ids, .probe = snd_ali_probe, .remove = __devexit_p(snd_ali_remove), diff --git a/trunk/sound/pci/als300.c b/trunk/sound/pci/als300.c index 736c8e93db1f..d7653cb7ac60 100644 --- a/trunk/sound/pci/als300.c +++ b/trunk/sound/pci/als300.c @@ -722,7 +722,7 @@ static int __devinit snd_als300_create(struct snd_card *card, irq_handler = snd_als300_interrupt; if (request_irq(pci->irq, irq_handler, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_als300_free(chip); return -EBUSY; @@ -846,7 +846,7 @@ static int __devinit snd_als300_probe(struct pci_dev *pci, } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ALS300", .id_table = snd_als300_ids, .probe = snd_als300_probe, .remove = __devexit_p(snd_als300_remove), diff --git a/trunk/sound/pci/als4000.c b/trunk/sound/pci/als4000.c index a9c1af33f276..0e247cb90ecc 100644 --- a/trunk/sound/pci/als4000.c +++ b/trunk/sound/pci/als4000.c @@ -1036,7 +1036,7 @@ static int snd_als4000_resume(struct pci_dev *pci) static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ALS4000", .id_table = snd_als4000_ids, .probe = snd_card_als4000_probe, .remove = __devexit_p(snd_card_als4000_remove), diff --git a/trunk/sound/pci/asihpi/asihpi.c b/trunk/sound/pci/asihpi/asihpi.c index b941d2541dda..e3569bdd3b64 100644 --- a/trunk/sound/pci/asihpi/asihpi.c +++ b/trunk/sound/pci/asihpi/asihpi.c @@ -49,21 +49,19 @@ 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 inline void -snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) +static void pcm_debug_name(struct snd_pcm_substream *substream, + char *name, size_t len) { - snprintf(buf, size, "pcmC%dD%d%c:%d", + 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 -static inline void -snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) -{ - *buf = 0; -} +#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 @@ -306,8 +304,7 @@ static u16 handle_error(u16 err, int line, char *filename) static void print_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *p) { - char name[16]; - snd_pcm_debug_name(substream, name, sizeof(name)); + 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)); @@ -579,9 +576,8 @@ 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; - char name[16]; + DEBUG_NAME(substream, name); - snd_pcm_debug_name(substream, name, sizeof(name)); snd_printdd("%s trigger\n", name); switch (cmd) { @@ -745,9 +741,7 @@ 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; - char name[16]; - - snd_pcm_debug_name(substream, name, sizeof(name)); + DEBUG_NAME(substream, name); snd_printdd("%s snd_card_asihpi_timer_function\n", name); @@ -1329,12 +1323,10 @@ static const char * const asihpi_src_names[] = { "RF", "Clock", "Bitstream", - "Mic", - "Net", + "Microphone", + "Cobranet", "Analog", "Adapter", - "RTP", - "GPI", }; compile_time_assert( @@ -1349,10 +1341,8 @@ static const char * const asihpi_dst_names[] = { "Digital", "RF", "Speaker", - "Net", - "Analog", - "RTP", - "GPO", + "Cobranet Out", + "Analog" }; compile_time_assert( @@ -1486,40 +1476,11 @@ static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0); -#define snd_asihpi_volume_mute_info snd_ctl_boolean_mono_info - -static int snd_asihpi_volume_mute_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u32 h_control = kcontrol->private_value; - u32 mute; - - hpi_handle_error(hpi_volume_get_mute(h_control, &mute)); - ucontrol->value.integer.value[0] = mute ? 0 : 1; - - return 0; -} - -static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u32 h_control = kcontrol->private_value; - int change = 1; - /* HPI currently only supports all or none muting of multichannel volume - ALSA Switch element has opposite sense to HPI mute: on==unmuted, off=muted - */ - int mute = ucontrol->value.integer.value[0] ? 0 : HPI_BITMASK_ALL_CHANNELS; - hpi_handle_error(hpi_volume_set_mute(h_control, mute)); - return change; -} - static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi, struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; - int err; - u32 mute; asihpi_ctl_init(&snd_control, hpi_ctl, "Volume"); snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -1529,19 +1490,7 @@ static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi, snd_control.put = snd_asihpi_volume_put; snd_control.tlv.p = db_scale_100; - err = ctl_add(card, &snd_control, asihpi); - if (err) - return err; - - if (hpi_volume_get_mute(hpi_ctl->h_control, &mute) == 0) { - asihpi_ctl_init(&snd_control, hpi_ctl, "Switch"); - snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; - snd_control.info = snd_asihpi_volume_mute_info; - snd_control.get = snd_asihpi_volume_mute_get; - snd_control.put = snd_asihpi_volume_mute_put; - err = ctl_add(card, &snd_control, asihpi); - } - return err; + return ctl_add(card, &snd_control, asihpi); } /*------------------------------------------------------------ @@ -2974,7 +2923,7 @@ static DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = { MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl); static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "asihpi", .id_table = asihpi_pci_tbl, .probe = snd_asihpi_probe, .remove = __devexit_p(snd_asihpi_remove), diff --git a/trunk/sound/pci/asihpi/hpi.h b/trunk/sound/pci/asihpi/hpi.h index f20727288994..255429c32c1c 100644 --- a/trunk/sound/pci/asihpi/hpi.h +++ b/trunk/sound/pci/asihpi/hpi.h @@ -1,7 +1,7 @@ /****************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -42,11 +42,12 @@ i.e 3.05.02 is a development version #define HPI_VER_MINOR(v) ((int)((v >> 8) & 0xFF)) #define HPI_VER_RELEASE(v) ((int)(v & 0xFF)) -#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 8, 0) -#define HPI_VER_STRING "4.08.00" +/* Use single digits for versions less that 10 to avoid octal. */ +#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 6, 0) +#define HPI_VER_STRING "4.06.00" /* Library version as documented in hpi-api-versions.txt */ -#define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(10, 0, 0) +#define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(9, 0, 0) #include #define HPI_BUILD_EXCLUDE_DEPRECATED @@ -210,12 +211,8 @@ enum HPI_SOURCENODES { HPI_SOURCENODE_COBRANET = 109, HPI_SOURCENODE_ANALOG = 110, /**< analog input node. */ HPI_SOURCENODE_ADAPTER = 111, /**< adapter node. */ - /** RTP stream input node - This node is a destination for - packets of RTP audio samples from other devices. */ - HPI_SOURCENODE_RTP_DESTINATION = 112, - HPI_SOURCENODE_GP_IN = 113, /**< general purpose input. */ /* !!!Update this AND hpidebug.h if you add a new sourcenode type!!! */ - HPI_SOURCENODE_LAST_INDEX = 113 /**< largest ID */ + HPI_SOURCENODE_LAST_INDEX = 111 /**< largest ID */ /* AX6 max sourcenode types = 15 */ }; @@ -231,7 +228,7 @@ enum HPI_DESTNODES { HPI_DESTNODE_NONE = 200, /** In Stream (Record) node. */ HPI_DESTNODE_ISTREAM = 201, - HPI_DESTNODE_LINEOUT = 202, /**< line out node. */ + HPI_DESTNODE_LINEOUT = 202, /**< line out node. */ HPI_DESTNODE_AESEBU_OUT = 203, /**< AES/EBU output node. */ HPI_DESTNODE_RF = 204, /**< RF output node. */ HPI_DESTNODE_SPEAKER = 205, /**< speaker output node. */ @@ -239,12 +236,9 @@ enum HPI_DESTNODES { Audio samples from the device are sent out on the Cobranet network.*/ HPI_DESTNODE_COBRANET = 206, HPI_DESTNODE_ANALOG = 207, /**< analog output node. */ - /** RTP stream output node - This node is a source for - packets of RTP audio samples that are sent to other devices. */ - HPI_DESTNODE_RTP_SOURCE = 208, - HPI_DESTNODE_GP_OUT = 209, /**< general purpose output node. */ + /* !!!Update this AND hpidebug.h if you add a new destnode type!!! */ - HPI_DESTNODE_LAST_INDEX = 209 /**< largest ID */ + HPI_DESTNODE_LAST_INDEX = 207 /**< largest ID */ /* AX6 max destnode types = 15 */ }; diff --git a/trunk/sound/pci/asihpi/hpi6000.c b/trunk/sound/pci/asihpi/hpi6000.c index 3cc6f11c20aa..df4aed5295dd 100644 --- a/trunk/sound/pci/asihpi/hpi6000.c +++ b/trunk/sound/pci/asihpi/hpi6000.c @@ -359,7 +359,7 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr) HPI_ERROR_PROCESSING_MESSAGE); switch (phm->type) { - case HPI_TYPE_REQUEST: + case HPI_TYPE_MESSAGE: switch (phm->object) { case HPI_OBJ_SUBSYSTEM: subsys_message(phm, phr); @@ -538,7 +538,7 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao, HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n"); memset(&hm, 0, sizeof(hm)); - hm.type = HPI_TYPE_REQUEST; + hm.type = HPI_TYPE_MESSAGE; hm.size = sizeof(struct hpi_message); hm.object = HPI_OBJ_ADAPTER; hm.function = HPI_ADAPTER_GET_INFO; @@ -946,8 +946,11 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao, } /* write the DSP code down into the DSPs memory */ - error = hpi_dsp_code_open(boot_load_family, pao->pci.pci_dev, - &dsp_code, pos_error_code); + /*HpiDspCode_Open(nBootLoadFamily,&DspCode,pdwOsErrorCode); */ + dsp_code.ps_dev = pao->pci.pci_dev; + + error = hpi_dsp_code_open(boot_load_family, &dsp_code, + pos_error_code); if (error) return error; diff --git a/trunk/sound/pci/asihpi/hpi6205.c b/trunk/sound/pci/asihpi/hpi6205.c index e041a6ae1c5a..9d5df54a6b46 100644 --- a/trunk/sound/pci/asihpi/hpi6205.c +++ b/trunk/sound/pci/asihpi/hpi6205.c @@ -373,7 +373,6 @@ static void instream_message(struct hpi_adapter_obj *pao, /** Entry point to this HPI backend * All calls to the HPI start here */ -static void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm, struct hpi_response *phr) { @@ -393,7 +392,7 @@ void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm, HPI_DEBUG_LOG(VERBOSE, "start of switch\n"); switch (phm->type) { - case HPI_TYPE_REQUEST: + case HPI_TYPE_MESSAGE: switch (phm->object) { case HPI_OBJ_SUBSYSTEM: subsys_message(pao, phm, phr); @@ -403,6 +402,7 @@ void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm, adapter_message(pao, phm, phr); break; + case HPI_OBJ_CONTROLEX: case HPI_OBJ_CONTROL: control_message(pao, phm, phr); break; @@ -634,12 +634,11 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n"); memset(&hm, 0, sizeof(hm)); - /* wAdapterIndex == version == 0 */ - hm.type = HPI_TYPE_REQUEST; + hm.type = HPI_TYPE_MESSAGE; hm.size = sizeof(hm); hm.object = HPI_OBJ_ADAPTER; hm.function = HPI_ADAPTER_GET_INFO; - + hm.adapter_index = 0; memset(&hr, 0, sizeof(hr)); hr.size = sizeof(hr); @@ -659,6 +658,9 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, hr.u.ax.info.num_outstreams + hr.u.ax.info.num_instreams; + hpios_locked_mem_prepare((max_streams * 6) / 10, max_streams, + 65536, pao->pci.pci_dev); + HPI_DEBUG_LOG(VERBOSE, "got adapter info type %x index %d serial %d\n", hr.u.ax.info.adapter_type, hr.u.ax.info.adapter_index, @@ -707,6 +709,9 @@ static void delete_adapter_obj(struct hpi_adapter_obj *pao) [i]); phw->outstream_host_buffer_size[i] = 0; } + + hpios_locked_mem_unprepare(pao->pci.pci_dev); + kfree(phw); } @@ -1366,8 +1371,9 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao, return err; /* write the DSP code down into the DSPs memory */ - err = hpi_dsp_code_open(boot_code_id[dsp], pao->pci.pci_dev, - &dsp_code, pos_error_code); + dsp_code.ps_dev = pao->pci.pci_dev; + err = hpi_dsp_code_open(boot_code_id[dsp], &dsp_code, + pos_error_code); if (err) return err; @@ -2078,13 +2084,13 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao, u16 err = 0; message_count++; - if (phm->size > sizeof(interface->u.message_buffer)) { + if (phm->size > sizeof(interface->u)) { phr->error = HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL; - phr->specific_error = sizeof(interface->u.message_buffer); + phr->specific_error = sizeof(interface->u); phr->size = sizeof(struct hpi_response_header); HPI_DEBUG_LOG(ERROR, "message len %d too big for buffer %zd \n", phm->size, - sizeof(interface->u.message_buffer)); + sizeof(interface->u)); return 0; } @@ -2116,19 +2122,18 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao, /* read the result */ if (time_out) { - if (interface->u.response_buffer.response.size <= phr->size) + if (interface->u.response_buffer.size <= phr->size) memcpy(phr, &interface->u.response_buffer, - interface->u.response_buffer.response.size); + interface->u.response_buffer.size); else { HPI_DEBUG_LOG(ERROR, "response len %d too big for buffer %d\n", - interface->u.response_buffer.response.size, - phr->size); + interface->u.response_buffer.size, phr->size); memcpy(phr, &interface->u.response_buffer, sizeof(struct hpi_response_header)); phr->error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL; phr->specific_error = - interface->u.response_buffer.response.size; + interface->u.response_buffer.size; phr->size = sizeof(struct hpi_response_header); } } @@ -2197,6 +2202,23 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, phm->u.d.u.data.data_size, H620_HIF_GET_DATA); break; + case HPI_CONTROL_SET_STATE: + if (phm->object == HPI_OBJ_CONTROLEX + && phm->u.cx.attribute == HPI_COBRANET_SET_DATA) + err = hpi6205_transfer_data(pao, + phm->u.cx.u.cobranet_bigdata.pb_data, + phm->u.cx.u.cobranet_bigdata.byte_count, + H620_HIF_SEND_DATA); + break; + + case HPI_CONTROL_GET_STATE: + if (phm->object == HPI_OBJ_CONTROLEX + && phm->u.cx.attribute == HPI_COBRANET_GET_DATA) + err = hpi6205_transfer_data(pao, + phm->u.cx.u.cobranet_bigdata.pb_data, + phr->u.cx.u.cobranet_data.byte_count, + H620_HIF_GET_DATA); + break; } phr->error = err; diff --git a/trunk/sound/pci/asihpi/hpi6205.h b/trunk/sound/pci/asihpi/hpi6205.h index ec0827b633a6..df2f02c0c7b4 100644 --- a/trunk/sound/pci/asihpi/hpi6205.h +++ b/trunk/sound/pci/asihpi/hpi6205.h @@ -1,7 +1,7 @@ /***************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -70,28 +70,15 @@ The Host located memory buffer that the 6205 will bus master in and out of. ************************************************************/ #define HPI6205_SIZEOF_DATA (16*1024) - -struct message_buffer_6205 { - struct hpi_message message; - char data[256]; -}; - -struct response_buffer_6205 { - struct hpi_response response; - char data[256]; -}; - -union buffer_6205 { - struct message_buffer_6205 message_buffer; - struct response_buffer_6205 response_buffer; - u8 b_data[HPI6205_SIZEOF_DATA]; -}; - struct bus_master_interface { u32 host_cmd; u32 dsp_ack; u32 transfer_size_in_bytes; - union buffer_6205 u; + union { + struct hpi_message_header message_buffer; + struct hpi_response_header response_buffer; + u8 b_data[HPI6205_SIZEOF_DATA]; + } u; struct controlcache_6205 control_cache; struct async_event_buffer_6205 async_buffer; struct hpi_hostbuffer_status diff --git a/trunk/sound/pci/asihpi/hpi_internal.h b/trunk/sound/pci/asihpi/hpi_internal.h index d497030c160f..bf5eced76bac 100644 --- a/trunk/sound/pci/asihpi/hpi_internal.h +++ b/trunk/sound/pci/asihpi/hpi_internal.h @@ -1,7 +1,7 @@ /****************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -32,6 +32,12 @@ HPI internal definitions #include "hpios.h" /* physical memory allocation */ +void hpios_locked_mem_init(void + ); +void hpios_locked_mem_free_all(void + ); +#define hpios_locked_mem_prepare(a, b, c, d); +#define hpios_locked_mem_unprepare(a) /** Allocate and map an area of locked memory for bus master DMA operations. @@ -220,8 +226,8 @@ enum HPI_CONTROL_ATTRIBUTES { HPI_COBRANET_SET = HPI_CTL_ATTR(COBRANET, 1), HPI_COBRANET_GET = HPI_CTL_ATTR(COBRANET, 2), - /*HPI_COBRANET_SET_DATA = HPI_CTL_ATTR(COBRANET, 3), */ - /*HPI_COBRANET_GET_DATA = HPI_CTL_ATTR(COBRANET, 4), */ + HPI_COBRANET_SET_DATA = HPI_CTL_ATTR(COBRANET, 3), + HPI_COBRANET_GET_DATA = HPI_CTL_ATTR(COBRANET, 4), HPI_COBRANET_GET_STATUS = HPI_CTL_ATTR(COBRANET, 5), HPI_COBRANET_SEND_PACKET = HPI_CTL_ATTR(COBRANET, 6), HPI_COBRANET_GET_PACKET = HPI_CTL_ATTR(COBRANET, 7), @@ -358,12 +364,10 @@ Used in DLL to indicate device not present #define HPI_ADAPTER_ASI(f) (f) enum HPI_MESSAGE_TYPES { - HPI_TYPE_REQUEST = 1, + HPI_TYPE_MESSAGE = 1, HPI_TYPE_RESPONSE = 2, HPI_TYPE_DATA = 3, - HPI_TYPE_SSX2BYPASS_MESSAGE = 4, - HPI_TYPE_COMMAND = 5, - HPI_TYPE_NOTIFICATION = 6 + HPI_TYPE_SSX2BYPASS_MESSAGE = 4 }; enum HPI_OBJECT_TYPES { @@ -379,7 +383,7 @@ enum HPI_OBJECT_TYPES { HPI_OBJ_WATCHDOG = 10, HPI_OBJ_CLOCK = 11, HPI_OBJ_PROFILE = 12, - /* HPI_ OBJ_ CONTROLEX = 13, */ + HPI_OBJ_CONTROLEX = 13, HPI_OBJ_ASYNCEVENT = 14 #define HPI_OBJ_MAXINDEX 14 }; @@ -604,7 +608,7 @@ struct hpi_data_compat32 { #endif struct hpi_buffer { - /** placeholder for backward compatibility (see dwBufferSize) */ + /** placehoder for backward compatibility (see dwBufferSize) */ struct hpi_msg_format reserved; u32 command; /**< HPI_BUFFER_CMD_xxx*/ u32 pci_address; /**< PCI physical address of buffer for DSP DMA */ @@ -908,13 +912,95 @@ union hpi_control_union_res { u32 remaining_chars; } chars8; char c_data12[12]; +}; + +/* HPI_CONTROLX_STRUCTURES */ + +/* Message */ + +/** Used for all HMI variables where max length <= 8 bytes +*/ +struct hpi_controlx_msg_cobranet_data { + u32 hmi_address; + u32 byte_count; + u32 data[2]; +}; + +/** Used for string data, and for packet bridge +*/ +struct hpi_controlx_msg_cobranet_bigdata { + u32 hmi_address; + u32 byte_count; + u8 *pb_data; +#ifndef HPI64BIT + u32 padding; +#endif +}; + +/** Used for PADS control reading of string fields. +*/ +struct hpi_controlx_msg_pad_data { + u32 field; + u32 byte_count; + u8 *pb_data; +#ifndef HPI64BIT + u32 padding; +#endif +}; + +/** Used for generic data +*/ + +struct hpi_controlx_msg_generic { + u32 param1; + u32 param2; +}; + +struct hpi_controlx_msg { + u16 attribute; /* control attribute or property */ + u16 saved_index; union { - struct { - u32 status; - u32 readable_size; - u32 writeable_size; - } status; - } cobranet; + struct hpi_controlx_msg_cobranet_data cobranet_data; + struct hpi_controlx_msg_cobranet_bigdata cobranet_bigdata; + struct hpi_controlx_msg_generic generic; + struct hpi_controlx_msg_pad_data pad_data; + /*struct param_value universal_value; */ + /* nothing extra to send for status read */ + } u; +}; + +/* Response */ +/** +*/ +struct hpi_controlx_res_cobranet_data { + u32 byte_count; + u32 data[2]; +}; + +struct hpi_controlx_res_cobranet_bigdata { + u32 byte_count; +}; + +struct hpi_controlx_res_cobranet_status { + u32 status; + u32 readable_size; + u32 writeable_size; +}; + +struct hpi_controlx_res_generic { + u32 param1; + u32 param2; +}; + +struct hpi_controlx_res { + union { + struct hpi_controlx_res_cobranet_bigdata cobranet_bigdata; + struct hpi_controlx_res_cobranet_data cobranet_data; + struct hpi_controlx_res_cobranet_status cobranet_status; + struct hpi_controlx_res_generic generic; + /*struct param_info universal_info; */ + /*struct param_value universal_value; */ + } u; }; struct hpi_nvmemory_msg { @@ -1040,6 +1126,7 @@ struct hpi_message { /* identical to struct hpi_control_msg, but field naming is improved */ struct hpi_control_union_msg cu; + struct hpi_controlx_msg cx; /* extended mixer control; */ struct hpi_nvmemory_msg n; struct hpi_gpio_msg l; /* digital i/o */ struct hpi_watchdog_msg w; @@ -1064,7 +1151,7 @@ struct hpi_message { sizeof(struct hpi_message_header) + sizeof(struct hpi_watchdog_msg),\ sizeof(struct hpi_message_header) + sizeof(struct hpi_clock_msg),\ sizeof(struct hpi_message_header) + sizeof(struct hpi_profile_msg),\ - sizeof(struct hpi_message_header), /* controlx obj removed */ \ + sizeof(struct hpi_message_header) + sizeof(struct hpi_controlx_msg),\ sizeof(struct hpi_message_header) + sizeof(struct hpi_async_msg) \ } @@ -1101,6 +1188,7 @@ struct hpi_response { struct hpi_control_res c; /* mixer control; */ /* identical to hpi_control_res, but field naming is improved */ union hpi_control_union_res cu; + struct hpi_controlx_res cx; /* extended mixer control; */ struct hpi_nvmemory_res n; struct hpi_gpio_res l; /* digital i/o */ struct hpi_watchdog_res w; @@ -1125,7 +1213,7 @@ struct hpi_response { sizeof(struct hpi_response_header) + sizeof(struct hpi_watchdog_res),\ sizeof(struct hpi_response_header) + sizeof(struct hpi_clock_res),\ sizeof(struct hpi_response_header) + sizeof(struct hpi_profile_res),\ - sizeof(struct hpi_response_header), /* controlx obj removed */ \ + sizeof(struct hpi_response_header) + sizeof(struct hpi_controlx_res),\ sizeof(struct hpi_response_header) + sizeof(struct hpi_async_res) \ } @@ -1220,30 +1308,6 @@ struct hpi_res_adapter_debug_read { u8 bytes[256]; }; -struct hpi_msg_cobranet_hmi { - u16 attribute; - u16 padding; - u32 hmi_address; - u32 byte_count; -}; - -struct hpi_msg_cobranet_hmiwrite { - struct hpi_message_header h; - struct hpi_msg_cobranet_hmi p; - u8 bytes[256]; -}; - -struct hpi_msg_cobranet_hmiread { - struct hpi_message_header h; - struct hpi_msg_cobranet_hmi p; -}; - -struct hpi_res_cobranet_hmiread { - struct hpi_response_header h; - u32 byte_count; - u8 bytes[256]; -}; - #if 1 #define hpi_message_header_v1 hpi_message_header #define hpi_response_header_v1 hpi_response_header @@ -1274,6 +1338,7 @@ struct hpi_msg_payload_v0 { union hpi_mixerx_msg mx; struct hpi_control_msg c; struct hpi_control_union_msg cu; + struct hpi_controlx_msg cx; struct hpi_nvmemory_msg n; struct hpi_gpio_msg l; struct hpi_watchdog_msg w; @@ -1293,6 +1358,7 @@ struct hpi_res_payload_v0 { union hpi_mixerx_res mx; struct hpi_control_res c; union hpi_control_union_res cu; + struct hpi_controlx_res cx; struct hpi_nvmemory_res n; struct hpi_gpio_res l; struct hpi_watchdog_res w; @@ -1427,6 +1493,12 @@ struct hpi_control_cache_microphone { char temp_padding[6]; }; +struct hpi_control_cache_generic { + struct hpi_control_cache_info i; + u32 dw1; + u32 dw2; +}; + struct hpi_control_cache_single { union { struct hpi_control_cache_info i; @@ -1442,6 +1514,7 @@ struct hpi_control_cache_single { struct hpi_control_cache_silencedetector silence; struct hpi_control_cache_sampleclock clk; struct hpi_control_cache_microphone microphone; + struct hpi_control_cache_generic generic; } u; }; diff --git a/trunk/sound/pci/asihpi/hpicmn.c b/trunk/sound/pci/asihpi/hpicmn.c index 65b7ca13115b..b15a02e91f82 100644 --- a/trunk/sound/pci/asihpi/hpicmn.c +++ b/trunk/sound/pci/asihpi/hpicmn.c @@ -57,7 +57,7 @@ u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr) } if (phr->function != phm->function) { - HPI_DEBUG_LOG(ERROR, "header function %d invalid\n", + HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->function); return HPI_ERROR_INVALID_RESPONSE; } @@ -315,7 +315,8 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, short found = 1; struct hpi_control_cache_info *pI; struct hpi_control_cache_single *pC; - size_t response_size; + struct hpi_control_cache_pad *p_pad; + if (!find_control(phm->obj_index, p_cache, &pI)) { HPI_DEBUG_LOG(VERBOSE, "HPICMN find_control() failed for adap %d\n", @@ -325,15 +326,11 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, phr->error = 0; - /* set the default response size */ - response_size = - sizeof(struct hpi_response_header) + - sizeof(struct hpi_control_res); - /* pC is the default cached control strucure. May be cast to something else in the following switch statement. */ pC = (struct hpi_control_cache_single *)pI; + p_pad = (struct hpi_control_cache_pad *)pI; switch (pI->control_type) { @@ -532,7 +529,9 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, pI->control_index, pI->control_type, phm->u.c.attribute); if (found) - phr->size = (u16)response_size; + phr->size = + sizeof(struct hpi_response_header) + + sizeof(struct hpi_control_res); return found; } @@ -683,7 +682,7 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr) { switch (phm->type) { - case HPI_TYPE_REQUEST: + case HPI_TYPE_MESSAGE: switch (phm->object) { case HPI_OBJ_SUBSYSTEM: subsys_message(phm, phr); diff --git a/trunk/sound/pci/asihpi/hpidspcd.c b/trunk/sound/pci/asihpi/hpidspcd.c index 3a7afa31c1d8..5c6ea113d219 100644 --- a/trunk/sound/pci/asihpi/hpidspcd.c +++ b/trunk/sound/pci/asihpi/hpidspcd.c @@ -1,8 +1,8 @@ /***********************************************************************/ -/** +/*! AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -18,59 +18,90 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \file -Functions for reading DSP code using +Functions for reading DSP code to load into DSP + +(Linux only:) If DSPCODE_FIRMWARE_LOADER is defined, code is read using hotplug firmware loader from individual dsp code files -*/ + +If neither of the above is defined, code is read from linked arrays. +DSPCODE_ARRAY is defined. + +HPI_INCLUDE_**** must be defined +and the appropriate hzz?????.c or hex?????.c linked in + + */ /***********************************************************************/ #define SOURCEFILE_NAME "hpidspcd.c" #include "hpidspcd.h" #include "hpidebug.h" -struct dsp_code_private { - /** Firmware descriptor */ - const struct firmware *firmware; - struct pci_dev *dev; +/** + Header structure for binary dsp code file (see asidsp.doc) + This structure must match that used in s2bin.c for generation of asidsp.bin + */ + +#ifndef DISABLE_PRAGMA_PACK1 +#pragma pack(push, 1) +#endif + +struct code_header { + u32 size; + char type[4]; + u32 adapter; + u32 version; + u32 crc; }; +#ifndef DISABLE_PRAGMA_PACK1 +#pragma pack(pop) +#endif + #define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \ HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER))) +/***********************************************************************/ +#include /*-------------------------------------------------------------------*/ -short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, - u32 *os_error_code) +short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code, + u32 *pos_error_code) { - const struct firmware *firmware; - struct pci_dev *dev = os_data; + const struct firmware *ps_firmware = ps_dsp_code->ps_firmware; struct code_header header; char fw_name[20]; int err; sprintf(fw_name, "asihpi/dsp%04x.bin", adapter); - err = request_firmware(&firmware, fw_name, &dev->dev); + err = request_firmware(&ps_firmware, fw_name, + &ps_dsp_code->ps_dev->dev); - if (err || !firmware) { - dev_printk(KERN_ERR, &dev->dev, + if (err != 0) { + dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, "%d, request_firmware failed for %s\n", err, fw_name); goto error1; } - if (firmware->size < sizeof(header)) { - dev_printk(KERN_ERR, &dev->dev, "Header size too small %s\n", - fw_name); + if (ps_firmware->size < sizeof(header)) { + dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, + "Header size too small %s\n", fw_name); goto error2; } - memcpy(&header, firmware->data, sizeof(header)); - - if ((header.type != 0x45444F43) || /* "CODE" */ - (header.adapter != adapter) - || (header.size != firmware->size)) { - dev_printk(KERN_ERR, &dev->dev, "Invalid firmware file\n"); + memcpy(&header, ps_firmware->data, sizeof(header)); + if (header.adapter != adapter) { + dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, + "Adapter type incorrect %4x != %4x\n", header.adapter, + adapter); + goto error2; + } + if (header.size != ps_firmware->size) { + dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, + "Code size wrong %d != %ld\n", header.size, + (unsigned long)ps_firmware->size); goto error2; } - if ((header.version / 100 & ~1) != (HPI_VER_DECIMAL / 100 & ~1)) { - dev_printk(KERN_ERR, &dev->dev, + if (header.version / 100 != HPI_VER_DECIMAL / 100) { + dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, "Incompatible firmware version " "DSP image %d != Driver %d\n", header.version, HPI_VER_DECIMAL); @@ -78,70 +109,67 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, } if (header.version != HPI_VER_DECIMAL) { - dev_printk(KERN_WARNING, &dev->dev, + dev_printk(KERN_WARNING, &ps_dsp_code->ps_dev->dev, "Firmware: release version mismatch DSP image %d != Driver %d\n", header.version, HPI_VER_DECIMAL); } HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name); - dsp_code->pvt = kmalloc(sizeof(*dsp_code->pvt), GFP_KERNEL); - if (!dsp_code->pvt) - return HPI_ERROR_MEMORY_ALLOC; - - dsp_code->pvt->dev = dev; - dsp_code->pvt->firmware = firmware; - dsp_code->header = header; - dsp_code->block_length = header.size / sizeof(u32); - dsp_code->word_count = sizeof(header) / sizeof(u32); + ps_dsp_code->ps_firmware = ps_firmware; + ps_dsp_code->block_length = header.size / sizeof(u32); + ps_dsp_code->word_count = sizeof(header) / sizeof(u32); + ps_dsp_code->version = header.version; + ps_dsp_code->crc = header.crc; return 0; error2: - release_firmware(firmware); + release_firmware(ps_firmware); error1: - dsp_code->block_length = 0; + ps_dsp_code->ps_firmware = NULL; + ps_dsp_code->block_length = 0; return HPI_ERROR_DSP_FILE_NOT_FOUND; } /*-------------------------------------------------------------------*/ -void hpi_dsp_code_close(struct dsp_code *dsp_code) +void hpi_dsp_code_close(struct dsp_code *ps_dsp_code) { - if (dsp_code->pvt->firmware) { + if (ps_dsp_code->ps_firmware != NULL) { HPI_DEBUG_LOG(DEBUG, "dsp code closed\n"); - release_firmware(dsp_code->pvt->firmware); - dsp_code->pvt->firmware = NULL; + release_firmware(ps_dsp_code->ps_firmware); + ps_dsp_code->ps_firmware = NULL; } - kfree(dsp_code->pvt); } /*-------------------------------------------------------------------*/ -void hpi_dsp_code_rewind(struct dsp_code *dsp_code) +void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code) { /* Go back to start of data, after header */ - dsp_code->word_count = sizeof(struct code_header) / sizeof(u32); + ps_dsp_code->word_count = sizeof(struct code_header) / sizeof(u32); } /*-------------------------------------------------------------------*/ -short hpi_dsp_code_read_word(struct dsp_code *dsp_code, u32 *pword) +short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code, u32 *pword) { - if (dsp_code->word_count + 1 > dsp_code->block_length) + if (ps_dsp_code->word_count + 1 > ps_dsp_code->block_length) return HPI_ERROR_DSP_FILE_FORMAT; - *pword = ((u32 *)(dsp_code->pvt->firmware->data))[dsp_code-> + *pword = ((u32 *)(ps_dsp_code->ps_firmware->data))[ps_dsp_code-> word_count]; - dsp_code->word_count++; + ps_dsp_code->word_count++; return 0; } /*-------------------------------------------------------------------*/ short hpi_dsp_code_read_block(size_t words_requested, - struct dsp_code *dsp_code, u32 **ppblock) + struct dsp_code *ps_dsp_code, u32 **ppblock) { - if (dsp_code->word_count + words_requested > dsp_code->block_length) + if (ps_dsp_code->word_count + words_requested > + ps_dsp_code->block_length) return HPI_ERROR_DSP_FILE_FORMAT; *ppblock = - ((u32 *)(dsp_code->pvt->firmware->data)) + - dsp_code->word_count; - dsp_code->word_count += words_requested; + ((u32 *)(ps_dsp_code->ps_firmware->data)) + + ps_dsp_code->word_count; + ps_dsp_code->word_count += words_requested; return 0; } diff --git a/trunk/sound/pci/asihpi/hpidspcd.h b/trunk/sound/pci/asihpi/hpidspcd.h index b22881122f19..65f0ca732704 100644 --- a/trunk/sound/pci/asihpi/hpidspcd.h +++ b/trunk/sound/pci/asihpi/hpidspcd.h @@ -2,7 +2,7 @@ /** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -20,6 +20,19 @@ \file Functions for reading DSP code to load into DSP + hpi_dspcode_defines HPI DSP code loading method +Define exactly one of these to select how the DSP code is supplied to +the adapter. + +End users writing applications that use the HPI interface do not have to +use any of the below defines; they are only necessary for building drivers + +HPI_DSPCODE_FILE: +DSP code is supplied as a file that is opened and read from by the driver. + +HPI_DSPCODE_FIRMWARE: +DSP code is read using the hotplug firmware loader module. + Only valid when compiling the HPI kernel driver under Linux. */ /***********************************************************************/ #ifndef _HPIDSPCD_H_ @@ -27,56 +40,37 @@ Functions for reading DSP code to load into DSP #include "hpi_internal.h" -/** Code header version is decimal encoded e.g. 4.06.10 is 40601 */ -#define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \ -HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER))) - -/** Header structure for dsp firmware file - This structure must match that used in s2bin.c for generation of asidsp.bin - */ -/*#ifndef DISABLE_PRAGMA_PACK1 */ -/*#pragma pack(push, 1) */ -/*#endif */ -struct code_header { - /** Size in bytes including header */ - u32 size; - /** File type tag "CODE" == 0x45444F43 */ - u32 type; - /** Adapter model number */ - u32 adapter; - /** Firmware version*/ - u32 version; - /** Data checksum */ - u32 checksum; -}; -/*#ifndef DISABLE_PRAGMA_PACK1 */ -/*#pragma pack(pop) */ -/*#endif */ - -/*? Don't need the pragmas? */ -compile_time_assert((sizeof(struct code_header) == 20), code_header_size); +#ifndef DISABLE_PRAGMA_PACK1 +#pragma pack(push, 1) +#endif /** Descriptor for dspcode from firmware loader */ struct dsp_code { - /** copy of file header */ - struct code_header header; + /** Firmware descriptor */ + const struct firmware *ps_firmware; + struct pci_dev *ps_dev; /** Expected number of words in the whole dsp code,INCL header */ - u32 block_length; + long int block_length; /** Number of words read so far */ - u32 word_count; - - /** internal state of DSP code reader */ - struct dsp_code_private *pvt; + long int word_count; + /** Version read from dsp code file */ + u32 version; + /** CRC read from dsp code file */ + u32 crc; }; -/** Prepare *psDspCode to refer to the requested adapter's firmware. -Code file name is obtained from HpiOs_GetDspCodePath +#ifndef DISABLE_PRAGMA_PACK1 +#pragma pack(pop) +#endif + +/** Prepare *psDspCode to refer to the requuested adapter. + Searches the file, or selects the appropriate linked array \return 0 for success, or error code if requested code is not available */ short hpi_dsp_code_open( /** Code identifier, usually adapter family */ - u32 adapter, void *pci_dev, + u32 adapter, /** Pointer to DSP code control structure */ struct dsp_code *ps_dsp_code, /** Pointer to dword to receive OS specific error code */ diff --git a/trunk/sound/pci/asihpi/hpifunc.c b/trunk/sound/pci/asihpi/hpifunc.c index ebb568d695f1..7397b169b89f 100644 --- a/trunk/sound/pci/asihpi/hpifunc.c +++ b/trunk/sound/pci/asihpi/hpifunc.c @@ -1663,64 +1663,68 @@ u16 hpi_channel_mode_get(u32 h_control, u16 *mode) u16 hpi_cobranet_hmi_write(u32 h_control, u32 hmi_address, u32 byte_count, u8 *pb_data) { - struct hpi_msg_cobranet_hmiwrite hm; - struct hpi_response_header hr; - - hpi_init_message_responseV1(&hm.h, sizeof(hm), &hr, sizeof(hr), - HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE); + struct hpi_message hm; + struct hpi_response hr; - if (hpi_handle_indexes(h_control, &hm.h.adapter_index, - &hm.h.obj_index)) + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, + HPI_CONTROL_SET_STATE); + if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index)) return HPI_ERROR_INVALID_HANDLE; - if (byte_count > sizeof(hm.bytes)) - return HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL; + hm.u.cx.u.cobranet_data.byte_count = byte_count; + hm.u.cx.u.cobranet_data.hmi_address = hmi_address; + + if (byte_count <= 8) { + memcpy(hm.u.cx.u.cobranet_data.data, pb_data, byte_count); + hm.u.cx.attribute = HPI_COBRANET_SET; + } else { + hm.u.cx.u.cobranet_bigdata.pb_data = pb_data; + hm.u.cx.attribute = HPI_COBRANET_SET_DATA; + } - hm.p.attribute = HPI_COBRANET_SET; - hm.p.byte_count = byte_count; - hm.p.hmi_address = hmi_address; - memcpy(hm.bytes, pb_data, byte_count); - hm.h.size = (u16)(sizeof(hm.h) + sizeof(hm.p) + byte_count); + hpi_send_recv(&hm, &hr); - hpi_send_recvV1(&hm.h, &hr); return hr.error; } u16 hpi_cobranet_hmi_read(u32 h_control, u32 hmi_address, u32 max_byte_count, u32 *pbyte_count, u8 *pb_data) { - struct hpi_msg_cobranet_hmiread hm; - struct hpi_res_cobranet_hmiread hr; - - hpi_init_message_responseV1(&hm.h, sizeof(hm), &hr.h, sizeof(hr), - HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); + struct hpi_message hm; + struct hpi_response hr; - if (hpi_handle_indexes(h_control, &hm.h.adapter_index, - &hm.h.obj_index)) + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, + HPI_CONTROL_GET_STATE); + if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index)) return HPI_ERROR_INVALID_HANDLE; - if (max_byte_count > sizeof(hr.bytes)) - return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL; + hm.u.cx.u.cobranet_data.byte_count = max_byte_count; + hm.u.cx.u.cobranet_data.hmi_address = hmi_address; - hm.p.attribute = HPI_COBRANET_GET; - hm.p.byte_count = max_byte_count; - hm.p.hmi_address = hmi_address; + if (max_byte_count <= 8) { + hm.u.cx.attribute = HPI_COBRANET_GET; + } else { + hm.u.cx.u.cobranet_bigdata.pb_data = pb_data; + hm.u.cx.attribute = HPI_COBRANET_GET_DATA; + } - hpi_send_recvV1(&hm.h, &hr.h); + hpi_send_recv(&hm, &hr); + if (!hr.error && pb_data) { - if (!hr.h.error && pb_data) { - if (hr.byte_count > sizeof(hr.bytes)) + *pbyte_count = hr.u.cx.u.cobranet_data.byte_count; - return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL; + if (*pbyte_count < max_byte_count) + max_byte_count = *pbyte_count; - *pbyte_count = hr.byte_count; + if (hm.u.cx.attribute == HPI_COBRANET_GET) { + memcpy(pb_data, hr.u.cx.u.cobranet_data.data, + max_byte_count); + } else { - if (hr.byte_count < max_byte_count) - max_byte_count = *pbyte_count; + } - memcpy(pb_data, hr.bytes, max_byte_count); } - return hr.h.error; + return hr.error; } u16 hpi_cobranet_hmi_get_status(u32 h_control, u32 *pstatus, @@ -1729,23 +1733,23 @@ u16 hpi_cobranet_hmi_get_status(u32 h_control, u32 *pstatus, struct hpi_message hm; struct hpi_response hr; - hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE); if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index)) return HPI_ERROR_INVALID_HANDLE; - hm.u.c.attribute = HPI_COBRANET_GET_STATUS; + hm.u.cx.attribute = HPI_COBRANET_GET_STATUS; hpi_send_recv(&hm, &hr); if (!hr.error) { if (pstatus) - *pstatus = hr.u.cu.cobranet.status.status; + *pstatus = hr.u.cx.u.cobranet_status.status; if (preadable_size) *preadable_size = - hr.u.cu.cobranet.status.readable_size; + hr.u.cx.u.cobranet_status.readable_size; if (pwriteable_size) *pwriteable_size = - hr.u.cu.cobranet.status.writeable_size; + hr.u.cx.u.cobranet_status.writeable_size; } return hr.error; } diff --git a/trunk/sound/pci/asihpi/hpimsginit.c b/trunk/sound/pci/asihpi/hpimsginit.c index 52400a6b5f15..628376ce4a49 100644 --- a/trunk/sound/pci/asihpi/hpimsginit.c +++ b/trunk/sound/pci/asihpi/hpimsginit.c @@ -46,7 +46,7 @@ static void hpi_init_message(struct hpi_message *phm, u16 object, if (gwSSX2_bypass) phm->type = HPI_TYPE_SSX2BYPASS_MESSAGE; else - phm->type = HPI_TYPE_REQUEST; + phm->type = HPI_TYPE_MESSAGE; phm->object = object; phm->function = function; phm->version = 0; @@ -89,7 +89,7 @@ static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size, memset(phm, 0, sizeof(*phm)); if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) { phm->size = size; - phm->type = HPI_TYPE_REQUEST; + phm->type = HPI_TYPE_MESSAGE; phm->object = object; phm->function = function; phm->version = 1; diff --git a/trunk/sound/pci/asihpi/hpimsgx.c b/trunk/sound/pci/asihpi/hpimsgx.c index 2e779421a618..7352a5f7b4f7 100644 --- a/trunk/sound/pci/asihpi/hpimsgx.c +++ b/trunk/sound/pci/asihpi/hpimsgx.c @@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -Extended Message Function With Response Caching +Extended Message Function With Response Cacheing (C) Copyright AudioScience Inc. 2002 *****************************************************************************/ @@ -186,6 +186,7 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr, /* Initialize this module's internal state */ hpios_msgxlock_init(&msgx_lock); memset(&hpi_entry_points, 0, sizeof(hpi_entry_points)); + hpios_locked_mem_init(); /* Init subsys_findadapters response to no-adapters */ HPIMSGX__reset(HPIMSGX_ALLADAPTERS); hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, @@ -196,6 +197,7 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr, case HPI_SUBSYS_DRIVER_UNLOAD: HPI_COMMON(phm, phr); HPIMSGX__cleanup(HPIMSGX_ALLADAPTERS, h_owner); + hpios_locked_mem_free_all(); hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_DRIVER_UNLOAD, 0); return; @@ -313,7 +315,7 @@ void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr, { HPI_DEBUG_MESSAGE(DEBUG, phm); - if (phm->type != HPI_TYPE_REQUEST) { + if (phm->type != HPI_TYPE_MESSAGE) { hpi_init_response(phr, phm->object, phm->function, HPI_ERROR_INVALID_TYPE); return; diff --git a/trunk/sound/pci/asihpi/hpioctl.c b/trunk/sound/pci/asihpi/hpioctl.c index 65fcf4770731..d8e7047512f8 100644 --- a/trunk/sound/pci/asihpi/hpioctl.c +++ b/trunk/sound/pci/asihpi/hpioctl.c @@ -1,7 +1,7 @@ /******************************************************************************* AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2010 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -157,6 +157,11 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto out; } + if (hm->h.adapter_index >= HPI_MAX_ADAPTERS) { + err = -EINVAL; + goto out; + } + switch (hm->h.function) { case HPI_SUBSYS_CREATE_ADAPTER: case HPI_ADAPTER_DELETE: @@ -182,6 +187,7 @@ 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 ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) { hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER, @@ -197,8 +203,6 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto out; } - pa = &adapters[adapter]; - if (mutex_lock_interruptible(&adapters[adapter].mutex)) { err = -EINTR; goto out; diff --git a/trunk/sound/pci/asihpi/hpios.c b/trunk/sound/pci/asihpi/hpios.c index ff2a19b544fa..742ee12a9e17 100644 --- a/trunk/sound/pci/asihpi/hpios.c +++ b/trunk/sound/pci/asihpi/hpios.c @@ -39,6 +39,10 @@ void hpios_delay_micro_seconds(u32 num_micro_sec) } +void hpios_locked_mem_init(void) +{ +} + /** Allocated an area of locked memory for bus master DMA operations. On error, return -ENOMEM, and *pMemArea.size = 0 @@ -81,3 +85,7 @@ u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area) return 1; } } + +void hpios_locked_mem_free_all(void) +{ +} diff --git a/trunk/sound/pci/asihpi/hpios.h b/trunk/sound/pci/asihpi/hpios.h index 2f605e34bad0..03273e729f99 100644 --- a/trunk/sound/pci/asihpi/hpios.h +++ b/trunk/sound/pci/asihpi/hpios.h @@ -38,7 +38,6 @@ HPI Operating System Specific macros for Linux Kernel driver #include #include #include -#include #define HPI_NO_OS_FILE_OPS diff --git a/trunk/sound/pci/atiixp.c b/trunk/sound/pci/atiixp.c index 537e0a2cc68a..3119cd97a217 100644 --- a/trunk/sound/pci/atiixp.c +++ b/trunk/sound/pci/atiixp.c @@ -1624,7 +1624,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card, } if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_atiixp_free(chip); return -EBUSY; @@ -1701,7 +1701,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ATI IXP AC97 controller", .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, .remove = __devexit_p(snd_atiixp_remove), diff --git a/trunk/sound/pci/atiixp_modem.c b/trunk/sound/pci/atiixp_modem.c index 45df275c8248..2f74c2fdf1ea 100644 --- a/trunk/sound/pci/atiixp_modem.c +++ b/trunk/sound/pci/atiixp_modem.c @@ -1260,7 +1260,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card, } if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_atiixp_free(chip); return -EBUSY; @@ -1332,7 +1332,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ATI IXP MC97 controller", .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, .remove = __devexit_p(snd_atiixp_remove), diff --git a/trunk/sound/pci/au88x0/au88x0.c b/trunk/sound/pci/au88x0/au88x0.c index a38469986885..7b72c88e449d 100644 --- a/trunk/sound/pci/au88x0/au88x0.c +++ b/trunk/sound/pci/au88x0/au88x0.c @@ -196,7 +196,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) } if ((err = request_irq(pci->irq, vortex_interrupt, - IRQF_SHARED, KBUILD_MODNAME, + IRQF_SHARED, CARD_NAME_SHORT, chip)) != 0) { printk(KERN_ERR "cannot grab irq\n"); goto irq_out; @@ -375,7 +375,7 @@ static void __devexit snd_vortex_remove(struct pci_dev *pci) // pci_driver definition static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = CARD_NAME_SHORT, .id_table = snd_vortex_ids, .probe = snd_vortex_probe, .remove = __devexit_p(snd_vortex_remove), diff --git a/trunk/sound/pci/aw2/aw2-alsa.c b/trunk/sound/pci/aw2/aw2-alsa.c index f8569b11331b..c15002242d98 100644 --- a/trunk/sound/pci/aw2/aw2-alsa.c +++ b/trunk/sound/pci/aw2/aw2-alsa.c @@ -171,7 +171,7 @@ MODULE_DEVICE_TABLE(pci, snd_aw2_ids); /* pci_driver definition */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Emagic Audiowerk 2", .id_table = snd_aw2_ids, .probe = snd_aw2_probe, .remove = __devexit_p(snd_aw2_remove), @@ -317,7 +317,7 @@ static int __devinit snd_aw2_create(struct snd_card *card, snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt); if (request_irq(pci->irq, snd_aw2_saa7146_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "Audiowerk2", chip)) { printk(KERN_ERR "aw2: Cannot grab irq %d\n", pci->irq); iounmap(chip->iobase_virt); diff --git a/trunk/sound/pci/azt3328.c b/trunk/sound/pci/azt3328.c index e4d76a270c9f..9b7a6346037a 100644 --- a/trunk/sound/pci/azt3328.c +++ b/trunk/sound/pci/azt3328.c @@ -2559,7 +2559,7 @@ snd_azf3328_create(struct snd_card *card, codec_setup->name = "I2S_OUT"; if (request_irq(pci->irq, snd_azf3328_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto out_err; @@ -2860,7 +2860,7 @@ snd_azf3328_resume(struct pci_dev *pci) static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "AZF3328", .id_table = snd_azf3328_ids, .probe = snd_azf3328_probe, .remove = __devexit_p(snd_azf3328_remove), diff --git a/trunk/sound/pci/bt87x.c b/trunk/sound/pci/bt87x.c index 39180335c237..2958a05b5293 100644 --- a/trunk/sound/pci/bt87x.c +++ b/trunk/sound/pci/bt87x.c @@ -760,7 +760,7 @@ static int __devinit snd_bt87x_create(struct snd_card *card, snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS); err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip); + "Bt87x audio", chip); if (err < 0) { snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq); goto fail; @@ -965,7 +965,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = { }; static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Bt87x", .id_table = snd_bt87x_ids, .probe = snd_bt87x_probe, .remove = __devexit_p(snd_bt87x_remove), diff --git a/trunk/sound/pci/ca0106/ca0106_main.c b/trunk/sound/pci/ca0106/ca0106_main.c index 061b7e654586..437759239694 100644 --- a/trunk/sound/pci/ca0106/ca0106_main.c +++ b/trunk/sound/pci/ca0106/ca0106_main.c @@ -1666,7 +1666,7 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, } if (request_irq(pci->irq, snd_ca0106_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "snd_ca0106", chip)) { snd_ca0106_free(chip); printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; @@ -1933,7 +1933,7 @@ MODULE_DEVICE_TABLE(pci, snd_ca0106_ids); // pci_driver definition static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "CA0106", .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, .remove = __devexit_p(snd_ca0106_remove), diff --git a/trunk/sound/pci/cmipci.c b/trunk/sound/pci/cmipci.c index 9cf99fb7eb9c..f4e573555da3 100644 --- a/trunk/sound/pci/cmipci.c +++ b/trunk/sound/pci/cmipci.c @@ -3053,7 +3053,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc cm->iobase = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_cmipci_interrupt, - IRQF_SHARED, KBUILD_MODNAME, cm)) { + IRQF_SHARED, card->driver, cm)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_cmipci_free(cm); return -EBUSY; @@ -3398,7 +3398,7 @@ static int snd_cmipci_resume(struct pci_dev *pci) #endif /* CONFIG_PM */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "C-Media PCI", .id_table = snd_cmipci_ids, .probe = snd_cmipci_probe, .remove = __devexit_p(snd_cmipci_remove), diff --git a/trunk/sound/pci/cs4281.c b/trunk/sound/pci/cs4281.c index 07f04e390aa1..6772070ed492 100644 --- a/trunk/sound/pci/cs4281.c +++ b/trunk/sound/pci/cs4281.c @@ -1382,7 +1382,7 @@ static int __devinit snd_cs4281_create(struct snd_card *card, } if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "CS4281", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_cs4281_free(chip); return -ENOMEM; @@ -2085,7 +2085,7 @@ static int cs4281_resume(struct pci_dev *pci) #endif /* CONFIG_PM */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "CS4281", .id_table = snd_cs4281_ids, .probe = snd_cs4281_probe, .remove = __devexit_p(snd_cs4281_remove), diff --git a/trunk/sound/pci/cs46xx/cs46xx.c b/trunk/sound/pci/cs46xx/cs46xx.c index 1af95559aaaa..767fa7f06cd0 100644 --- a/trunk/sound/pci/cs46xx/cs46xx.c +++ b/trunk/sound/pci/cs46xx/cs46xx.c @@ -162,7 +162,7 @@ static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Sound Fusion CS46xx", .id_table = snd_cs46xx_ids, .probe = snd_card_cs46xx_probe, .remove = __devexit_p(snd_card_cs46xx_remove), diff --git a/trunk/sound/pci/cs46xx/cs46xx_lib.c b/trunk/sound/pci/cs46xx/cs46xx_lib.c index 9546bf07f0d1..aad37082cb6e 100644 --- a/trunk/sound/pci/cs46xx/cs46xx_lib.c +++ b/trunk/sound/pci/cs46xx/cs46xx_lib.c @@ -3835,7 +3835,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card, } if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "CS46XX", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_cs46xx_free(chip); return -EBUSY; diff --git a/trunk/sound/pci/cs5530.c b/trunk/sound/pci/cs5530.c index a4669346d146..bc07e275d4d4 100644 --- a/trunk/sound/pci/cs5530.c +++ b/trunk/sound/pci/cs5530.c @@ -285,7 +285,7 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci, } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "CS5530_Audio", .id_table = snd_cs5530_ids, .probe = snd_cs5530_probe, .remove = __devexit_p(snd_cs5530_remove), diff --git a/trunk/sound/pci/cs5535audio/cs5535audio.c b/trunk/sound/pci/cs5535audio/cs5535audio.c index 10d22ed5fece..afb803708416 100644 --- a/trunk/sound/pci/cs5535audio/cs5535audio.c +++ b/trunk/sound/pci/cs5535audio/cs5535audio.c @@ -311,7 +311,7 @@ static int __devinit snd_cs5535audio_create(struct snd_card *card, cs5535au->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_cs5535audio_interrupt, - IRQF_SHARED, KBUILD_MODNAME, cs5535au)) { + IRQF_SHARED, "CS5535 Audio", cs5535au)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto sndfail; @@ -395,7 +395,7 @@ static void __devexit snd_cs5535audio_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = DRIVER_NAME, .id_table = snd_cs5535audio_ids, .probe = snd_cs5535audio_probe, .remove = __devexit_p(snd_cs5535audio_remove), diff --git a/trunk/sound/pci/ctxfi/ct20k2reg.h b/trunk/sound/pci/ctxfi/ct20k2reg.h index ca501ba03d64..e0394e3996e8 100644 --- a/trunk/sound/pci/ctxfi/ct20k2reg.h +++ b/trunk/sound/pci/ctxfi/ct20k2reg.h @@ -55,7 +55,6 @@ /* GPIO Registers */ #define GPIO_DATA 0x1B7020 #define GPIO_CTRL 0x1B7024 -#define GPIO_EXT_DATA 0x1B70A0 /* Virtual memory registers */ #define VMEM_PTPAL 0x1C6300 /* 0x1C6300 + (16 * Chn) */ diff --git a/trunk/sound/pci/ctxfi/ctatc.c b/trunk/sound/pci/ctxfi/ctatc.c index d8a4423539ce..13f33c0719d3 100644 --- a/trunk/sound/pci/ctxfi/ctatc.c +++ b/trunk/sound/pci/ctxfi/ctatc.c @@ -18,6 +18,7 @@ #include "ctatc.h" #include "ctpcm.h" #include "ctmixer.h" +#include "cthardware.h" #include "ctsrc.h" #include "ctamixer.h" #include "ctdaio.h" @@ -29,6 +30,7 @@ #include #define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ +#define DAIONUM 7 #define MAX_MULTI_CHN 8 #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \ @@ -51,8 +53,6 @@ static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, "SB0760", CTSB0760), - SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270, - "SB1270", CTSB1270), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801, "SB0880", CTSB0880), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802, @@ -75,7 +75,6 @@ static const char *ct_subsys_name[NUM_CTCARDS] = { [CTSB0760] = "SB076x", [CTHENDRIX] = "Hendrix", [CTSB0880] = "SB0880", - [CTSB1270] = "SB1270", [CT20K2_UNKNOWN] = "Unknown", }; @@ -460,12 +459,12 @@ static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm, apcm->substream->runtime->rate); *n_srcc = 0; - if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */ + if (1 == atc->msr) { *n_srcc = apcm->substream->runtime->channels; conf[0].pitch = pitch; conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1; conf[0].vo = 1; - } else if (2 <= atc->msr) { + } else if (2 == atc->msr) { if (0x8000000 < pitch) { /* Need two-stage SRCs, SRCIMPs and * AMIXERs for converting format */ @@ -971,39 +970,11 @@ static int atc_select_mic_in(struct ct_atc *atc) return 0; } -static struct capabilities atc_capabilities(struct ct_atc *atc) +static int atc_have_digit_io_switch(struct ct_atc *atc) { struct hw *hw = atc->hw; - return hw->capabilities(hw); -} - -static int atc_output_switch_get(struct ct_atc *atc) -{ - struct hw *hw = atc->hw; - - return hw->output_switch_get(hw); -} - -static int atc_output_switch_put(struct ct_atc *atc, int position) -{ - struct hw *hw = atc->hw; - - return hw->output_switch_put(hw, position); -} - -static int atc_mic_source_switch_get(struct ct_atc *atc) -{ - struct hw *hw = atc->hw; - - return hw->mic_source_switch_get(hw); -} - -static int atc_mic_source_switch_put(struct ct_atc *atc, int position) -{ - struct hw *hw = atc->hw; - - return hw->mic_source_switch_put(hw, position); + return hw->have_digit_io_switch(hw); } static int atc_select_digit_io(struct ct_atc *atc) @@ -1074,11 +1045,6 @@ static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state) return atc_daio_unmute(atc, state, LINEIM); } -static int atc_mic_unmute(struct ct_atc *atc, unsigned char state) -{ - return atc_daio_unmute(atc, state, MIC); -} - static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) { return atc_daio_unmute(atc, state, SPDIFOO); @@ -1365,20 +1331,17 @@ static int atc_get_resources(struct ct_atc *atc) struct srcimp_mgr *srcimp_mgr; struct sum_desc sum_dsc = {0}; struct sum_mgr *sum_mgr; - int err, i, num_srcs, num_daios; + int err, i; - num_daios = ((atc->model == CTSB1270) ? 8 : 7); - num_srcs = ((atc->model == CTSB1270) ? 6 : 4); - - atc->daios = kzalloc(sizeof(void *)*num_daios, GFP_KERNEL); + atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL); if (!atc->daios) return -ENOMEM; - atc->srcs = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL); + atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); if (!atc->srcs) return -ENOMEM; - atc->srcimps = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL); + atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); if (!atc->srcimps) return -ENOMEM; @@ -1388,9 +1351,8 @@ static int atc_get_resources(struct ct_atc *atc) daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; da_desc.msr = atc->msr; - for (i = 0, atc->n_daio = 0; i < num_daios; i++) { - da_desc.type = (atc->model != CTSB073X) ? i : - ((i == SPDIFIO) ? SPDIFI1 : i); + for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) { + da_desc.type = i; err = daio_mgr->get_daio(daio_mgr, &da_desc, (struct daio **)&atc->daios[i]); if (err) { @@ -1400,12 +1362,23 @@ static int atc_get_resources(struct ct_atc *atc) } atc->n_daio++; } + if (atc->model == CTSB073X) + da_desc.type = SPDIFI1; + else + da_desc.type = SPDIFIO; + err = daio_mgr->get_daio(daio_mgr, &da_desc, + (struct daio **)&atc->daios[i]); + if (err) { + printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n"); + return err; + } + atc->n_daio++; src_mgr = atc->rsc_mgrs[SRC]; src_dsc.multi = 1; src_dsc.msr = atc->msr; src_dsc.mode = ARCRW; - for (i = 0, atc->n_src = 0; i < num_srcs; i++) { + for (i = 0, atc->n_src = 0; i < (2*2); i++) { err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&atc->srcs[i]); if (err) @@ -1415,8 +1388,8 @@ static int atc_get_resources(struct ct_atc *atc) } srcimp_mgr = atc->rsc_mgrs[SRCIMP]; - srcimp_dsc.msr = 8; - for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) { + srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */ + for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) { err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, (struct srcimp **)&atc->srcimps[i]); if (err) @@ -1424,6 +1397,15 @@ static int atc_get_resources(struct ct_atc *atc) atc->n_srcimp++; } + srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */ + for (i = 0; i < (2*1); i++) { + err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, + (struct srcimp **)&atc->srcimps[2*1+i]); + if (err) + return err; + + atc->n_srcimp++; + } sum_mgr = atc->rsc_mgrs[SUM]; sum_dsc.msr = atc->msr; @@ -1506,18 +1488,6 @@ static void atc_connect_resources(struct ct_atc *atc) src = atc->srcs[3]; mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); - if (atc->model == CTSB1270) { - /* Titanium HD has a dedicated ADC for the Mic. */ - dai = container_of(atc->daios[MIC], struct dai, daio); - atc_connect_dai(atc->rsc_mgrs[SRC], dai, - (struct src **)&atc->srcs[4], - (struct srcimp **)&atc->srcimps[4]); - src = atc->srcs[4]; - mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); - src = atc->srcs[5]; - mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); - } - dai = container_of(atc->daios[SPDIFIO], struct dai, daio); atc_connect_dai(atc->rsc_mgrs[SRC], dai, (struct src **)&atc->srcs[0], @@ -1636,17 +1606,12 @@ static struct ct_atc atc_preset __devinitdata = { .line_clfe_unmute = atc_line_clfe_unmute, .line_rear_unmute = atc_line_rear_unmute, .line_in_unmute = atc_line_in_unmute, - .mic_unmute = atc_mic_unmute, .spdif_out_unmute = atc_spdif_out_unmute, .spdif_in_unmute = atc_spdif_in_unmute, .spdif_out_get_status = atc_spdif_out_get_status, .spdif_out_set_status = atc_spdif_out_set_status, .spdif_out_passthru = atc_spdif_out_passthru, - .capabilities = atc_capabilities, - .output_switch_get = atc_output_switch_get, - .output_switch_put = atc_output_switch_put, - .mic_source_switch_get = atc_mic_source_switch_get, - .mic_source_switch_put = atc_mic_source_switch_put, + .have_digit_io_switch = atc_have_digit_io_switch, #ifdef CONFIG_PM .suspend = atc_suspend, .resume = atc_resume, diff --git a/trunk/sound/pci/ctxfi/ctatc.h b/trunk/sound/pci/ctxfi/ctatc.h index 3a0def656af0..7167c0185d52 100644 --- a/trunk/sound/pci/ctxfi/ctatc.h +++ b/trunk/sound/pci/ctxfi/ctatc.h @@ -25,7 +25,6 @@ #include #include "ctvmem.h" -#include "cthardware.h" #include "ctresource.h" enum CTALSADEVS { /* Types of alsa devices */ @@ -116,17 +115,12 @@ struct ct_atc { int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state); int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state); int (*line_in_unmute)(struct ct_atc *atc, unsigned char state); - int (*mic_unmute)(struct ct_atc *atc, unsigned char state); int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state); int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state); int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status); int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status); int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state); - struct capabilities (*capabilities)(struct ct_atc *atc); - int (*output_switch_get)(struct ct_atc *atc); - int (*output_switch_put)(struct ct_atc *atc, int position); - int (*mic_source_switch_get)(struct ct_atc *atc); - int (*mic_source_switch_put)(struct ct_atc *atc, int position); + int (*have_digit_io_switch)(struct ct_atc *atc); /* Don't touch! Used for internal object. */ void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */ diff --git a/trunk/sound/pci/ctxfi/ctdaio.c b/trunk/sound/pci/ctxfi/ctdaio.c index 0c00eb4088ef..47d9ea97de02 100644 --- a/trunk/sound/pci/ctxfi/ctdaio.c +++ b/trunk/sound/pci/ctxfi/ctdaio.c @@ -22,9 +22,20 @@ #include #include +#define DAIO_RESOURCE_NUM NUM_DAIOTYP #define DAIO_OUT_MAX SPDIFOO -struct daio_usage { +union daio_usage { + struct { + unsigned short lineo1:1; + unsigned short lineo2:1; + unsigned short lineo3:1; + unsigned short lineo4:1; + unsigned short spdifoo:1; + unsigned short lineim:1; + unsigned short spdifio:1; + unsigned short spdifi1:1; + } bf; unsigned short data; }; @@ -50,7 +61,6 @@ struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = { [LINEO3] = {.left = 0x50, .right = 0x51}, [LINEO4] = {.left = 0x70, .right = 0x71}, [LINEIM] = {.left = 0x45, .right = 0xc5}, - [MIC] = {.left = 0x55, .right = 0xd5}, [SPDIFOO] = {.left = 0x00, .right = 0x01}, [SPDIFIO] = {.left = 0x05, .right = 0x85}, }; @@ -128,7 +138,6 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw) case LINEO3: return 5; case LINEO4: return 6; case LINEIM: return 4; - case MIC: return 5; default: return -EINVAL; } default: @@ -510,17 +519,17 @@ static int dai_rsc_uninit(struct dai *dai) static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) { - if (((struct daio_usage *)mgr->rscs)->data & (0x1 << type)) + if (((union daio_usage *)mgr->rscs)->data & (0x1 << type)) return -ENOENT; - ((struct daio_usage *)mgr->rscs)->data |= (0x1 << type); + ((union daio_usage *)mgr->rscs)->data |= (0x1 << type); return 0; } static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) { - ((struct daio_usage *)mgr->rscs)->data &= ~(0x1 << type); + ((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type); return 0; } @@ -703,7 +712,7 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr) if (!daio_mgr) return -ENOMEM; - err = rsc_mgr_init(&daio_mgr->mgr, DAIO, NUM_DAIOTYP, hw); + err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw); if (err) goto error1; diff --git a/trunk/sound/pci/ctxfi/ctdaio.h b/trunk/sound/pci/ctxfi/ctdaio.h index 85ccb6ee1ab4..0f52ce571ee8 100644 --- a/trunk/sound/pci/ctxfi/ctdaio.h +++ b/trunk/sound/pci/ctxfi/ctdaio.h @@ -33,7 +33,6 @@ enum DAIOTYP { SPDIFOO, /* S/PDIF Out (Flexijack/Optical) */ LINEIM, SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */ - MIC, /* Dedicated mic on Titanium HD */ SPDIFI1, /* S/PDIF In on internal Drive Bay */ NUM_DAIOTYP }; diff --git a/trunk/sound/pci/ctxfi/cthardware.h b/trunk/sound/pci/ctxfi/cthardware.h index 908315bec3b4..af55405f5dec 100644 --- a/trunk/sound/pci/ctxfi/cthardware.h +++ b/trunk/sound/pci/ctxfi/cthardware.h @@ -39,7 +39,6 @@ enum CTCARDS { CT20K2_MODEL_FIRST = CTSB0760, CTHENDRIX, CTSB0880, - CTSB1270, CT20K2_UNKNOWN, NUM_CTCARDS /* This should always be the last */ }; @@ -61,13 +60,6 @@ struct card_conf { unsigned int msr; /* master sample rate in rsrs */ }; -struct capabilities { - unsigned int digit_io_switch:1; - unsigned int dedicated_mic:1; - unsigned int output_switch:1; - unsigned int mic_source_switch:1; -}; - struct hw { int (*card_init)(struct hw *hw, struct card_conf *info); int (*card_stop)(struct hw *hw); @@ -78,11 +70,7 @@ struct hw { #endif int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source); int (*select_adc_source)(struct hw *hw, enum ADCSRC source); - struct capabilities (*capabilities)(struct hw *hw); - int (*output_switch_get)(struct hw *hw); - int (*output_switch_put)(struct hw *hw, int position); - int (*mic_source_switch_get)(struct hw *hw); - int (*mic_source_switch_put)(struct hw *hw, int position); + int (*have_digit_io_switch)(struct hw *hw); /* SRC operations */ int (*src_rsc_get_ctrl_blk)(void **rblk); diff --git a/trunk/sound/pci/ctxfi/cthw20k1.c b/trunk/sound/pci/ctxfi/cthw20k1.c index a7df19791f5a..a5c957db5cea 100644 --- a/trunk/sound/pci/ctxfi/cthw20k1.c +++ b/trunk/sound/pci/ctxfi/cthw20k1.c @@ -1777,17 +1777,10 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) return adc_init_SBx(hw, info->input, info->mic20db); } -static struct capabilities hw_capabilities(struct hw *hw) +static int hw_have_digit_io_switch(struct hw *hw) { - struct capabilities cap; - /* SB073x and Vista compatible cards have no digit IO switch */ - cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA); - cap.dedicated_mic = 0; - cap.output_switch = 0; - cap.mic_source_switch = 0; - - return cap; + return !(hw->model == CTSB073X || hw->model == CTUAA); } #define CTLBITS(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) @@ -1940,7 +1933,7 @@ static int hw_card_start(struct hw *hw) if (hw->irq < 0) { err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, - KBUILD_MODNAME, hw); + "ctxfi", hw); if (err < 0) { printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); goto error2; @@ -2179,7 +2172,7 @@ static struct hw ct20k1_preset __devinitdata = { .pll_init = hw_pll_init, .is_adc_source_selected = hw_is_adc_input_selected, .select_adc_source = hw_adc_input_select, - .capabilities = hw_capabilities, + .have_digit_io_switch = hw_have_digit_io_switch, #ifdef CONFIG_PM .suspend = hw_suspend, .resume = hw_resume, diff --git a/trunk/sound/pci/ctxfi/cthw20k2.c b/trunk/sound/pci/ctxfi/cthw20k2.c index d6c54b524bfa..5364164674e4 100644 --- a/trunk/sound/pci/ctxfi/cthw20k2.c +++ b/trunk/sound/pci/ctxfi/cthw20k2.c @@ -8,7 +8,7 @@ * @File cthw20k2.c * * @Brief - * This file contains the implementation of hardware access method for 20k2. + * This file contains the implementation of hardware access methord for 20k2. * * @Author Liu Chun * @Date May 14 2008 @@ -38,8 +38,6 @@ struct hw20k2 { unsigned char dev_id; unsigned char addr_size; unsigned char data_size; - - int mic_source; }; static u32 hw_read_20kx(struct hw *hw, u32 reg); @@ -1165,12 +1163,7 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101); hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); } else if (2 == info->msr) { - if (hw->model != CTSB1270) { - hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111); - } else { - /* PCM4220 on Titanium HD is different. */ - hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111); - } + hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111); /* Specify all playing 96khz * EA [0] - Enabled * RTA [4:5] - 96kHz @@ -1182,10 +1175,6 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) * RTD [28:29] - 96kHz */ hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111); hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); - } else if ((4 == info->msr) && (hw->model == CTSB1270)) { - hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111); - hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121); - hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); } else { printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n"); return -EINVAL; @@ -1193,8 +1182,6 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) for (i = 0; i < 8; i++) { if (i <= 3) { - /* This comment looks wrong since loop is over 4 */ - /* channels and emu20k2 supports 4 spdif IOs. */ /* 1st 3 channels are SPDIFs (SB0960) */ if (i == 3) data = 0x1001001; @@ -1219,16 +1206,12 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B); } else { - /* Again, loop is over 4 channels not 5. */ /* Next 5 channels are I2S (SB0960) */ data = 0x11; hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data); if (2 == info->msr) { /* Four channels per sample period */ data |= 0x1000; - } else if (4 == info->msr) { - /* FIXME: check this against the chip spec */ - data |= 0x2000; } hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data); } @@ -1316,18 +1299,21 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr) pllenb = 0xB; hw_write_20kx(hw, PLL_ENB, pllenb); - pllctl = 0x20C00000; - set_field(&pllctl, PLLCTL_B, 0); - set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 4 : 147 - 4); - set_field(&pllctl, PLLCTL_RD, 48000 == rsr ? 1 - 1 : 10 - 1); + pllctl = 0x20D00000; + set_field(&pllctl, PLLCTL_FD, 16 - 4); hw_write_20kx(hw, PLL_CTL, pllctl); mdelay(40); - pllctl = hw_read_20kx(hw, PLL_CTL); - set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 2 : 147 - 2); + set_field(&pllctl, PLLCTL_B, 0); + if (48000 == rsr) { + set_field(&pllctl, PLLCTL_FD, 16 - 2); + set_field(&pllctl, PLLCTL_RD, 1 - 1); /* 3000*16/1 = 48000 */ + } else { /* 44100 */ + set_field(&pllctl, PLLCTL_FD, 147 - 2); + set_field(&pllctl, PLLCTL_RD, 10 - 1); /* 3000*147/10 = 44100 */ + } hw_write_20kx(hw, PLL_CTL, pllctl); mdelay(40); - for (i = 0; i < 1000; i++) { pllstat = hw_read_20kx(hw, PLL_STAT); if (get_field(pllstat, PLLSTAT_PD)) @@ -1571,7 +1557,7 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data) hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); hw20k2_i2c_wait_data_ready(hw); - /* Dummy write to trigger the write operation */ + /* Dummy write to trigger the write oprtation */ hw_write_20kx(hw, I2C_IF_WDATA, 0); hw20k2_i2c_wait_data_ready(hw); @@ -1582,30 +1568,6 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data) return 0; } -static void hw_dac_stop(struct hw *hw) -{ - u32 data; - data = hw_read_20kx(hw, GPIO_DATA); - data &= 0xFFFFFFFD; - hw_write_20kx(hw, GPIO_DATA, data); - mdelay(10); -} - -static void hw_dac_start(struct hw *hw) -{ - u32 data; - data = hw_read_20kx(hw, GPIO_DATA); - data |= 0x2; - hw_write_20kx(hw, GPIO_DATA, data); - mdelay(50); -} - -static void hw_dac_reset(struct hw *hw) -{ - hw_dac_stop(hw); - hw_dac_start(hw); -} - static int hw_dac_init(struct hw *hw, const struct dac_conf *info) { int err; @@ -1632,21 +1594,6 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info) 0x00000000 /* Vol Control B4 */ }; - if (hw->model == CTSB1270) { - hw_dac_stop(hw); - data = hw_read_20kx(hw, GPIO_DATA); - data &= ~0x0600; - if (1 == info->msr) - data |= 0x0000; /* Single Speed Mode 0-50kHz */ - else if (2 == info->msr) - data |= 0x0200; /* Double Speed Mode 50-100kHz */ - else - data |= 0x0600; /* Quad Speed Mode 100-200kHz */ - hw_write_20kx(hw, GPIO_DATA, data); - hw_dac_start(hw); - return 0; - } - /* Set DAC reset bit as output */ data = hw_read_20kx(hw, GPIO_CTRL); data |= 0x02; @@ -1659,8 +1606,22 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info) for (i = 0; i < 2; i++) { /* Reset DAC twice just in-case the chip * didn't initialized properly */ - hw_dac_reset(hw); - hw_dac_reset(hw); + data = hw_read_20kx(hw, GPIO_DATA); + /* GPIO data bit 1 */ + data &= 0xFFFFFFFD; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(10); + data |= 0x2; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(50); + + /* Reset the 2nd time */ + data &= 0xFFFFFFFD; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(10); + data |= 0x2; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(50); if (hw20k2_i2c_read(hw, CS4382_MC1, &cs_read.mode_control_1)) continue; @@ -1764,11 +1725,7 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info) static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) { u32 data; - if (hw->model == CTSB1270) { - /* Titanium HD has two ADC chips, one for line in and one */ - /* for MIC. We don't need to switch the ADC input. */ - return 1; - } + data = hw_read_20kx(hw, GPIO_DATA); switch (type) { case ADC_MICIN: @@ -1785,47 +1742,35 @@ static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) #define MIC_BOOST_0DB 0xCF #define MIC_BOOST_STEPS_PER_DB 2 - -static void hw_wm8775_input_select(struct hw *hw, u8 input, s8 gain_in_db) -{ - u32 adcmc, gain; - - if (input > 3) - input = 3; - - adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */ - - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc), - MAKE_WM8775_DATA(adcmc)); - - if (gain_in_db < -103) - gain_in_db = -103; - if (gain_in_db > 24) - gain_in_db = 24; - - gain = gain_in_db * MIC_BOOST_STEPS_PER_DB + MIC_BOOST_0DB; - - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain), - MAKE_WM8775_DATA(gain)); - /* ...so there should be no need for the following. */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain), - MAKE_WM8775_DATA(gain)); -} +#define MIC_BOOST_20DB (MIC_BOOST_0DB + 20 * MIC_BOOST_STEPS_PER_DB) static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) { u32 data; + data = hw_read_20kx(hw, GPIO_DATA); switch (type) { case ADC_MICIN: data |= (0x1 << 14); hw_write_20kx(hw, GPIO_DATA, data); - hw_wm8775_input_select(hw, 0, 20); /* Mic, 20dB */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), + MAKE_WM8775_DATA(0x101)); /* Mic-in */ + hw20k2_i2c_write(hw, + MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB), + MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ + hw20k2_i2c_write(hw, + MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB), + MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ break; case ADC_LINEIN: data &= ~(0x1 << 14); hw_write_20kx(hw, GPIO_DATA, data); - hw_wm8775_input_select(hw, 1, 0); /* Line-in, 0dB */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), + MAKE_WM8775_DATA(0x102)); /* Line-in */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ break; default: break; @@ -1837,7 +1782,7 @@ static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) static int hw_adc_init(struct hw *hw, const struct adc_conf *info) { int err; - u32 data, ctl; + u32 mux = 2, data, ctl; /* Set ADC reset bit as output */ data = hw_read_20kx(hw, GPIO_CTRL); @@ -1851,42 +1796,19 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) goto error; } - /* Reset the ADC (reset is active low). */ + /* Make ADC in normal operation */ data = hw_read_20kx(hw, GPIO_DATA); data &= ~(0x1 << 15); - hw_write_20kx(hw, GPIO_DATA, data); - - if (hw->model == CTSB1270) { - /* Set up the PCM4220 ADC on Titanium HD */ - data &= ~0x0C; - if (1 == info->msr) - data |= 0x00; /* Single Speed Mode 32-50kHz */ - else if (2 == info->msr) - data |= 0x08; /* Double Speed Mode 50-108kHz */ - else - data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */ - hw_write_20kx(hw, GPIO_DATA, data); - } - mdelay(10); - /* Return the ADC to normal operation. */ data |= (0x1 << 15); hw_write_20kx(hw, GPIO_DATA, data); mdelay(50); - /* I2C write to register offset 0x0B to set ADC LRCLK polarity */ - /* invert bit, interface format to I2S, word length to 24-bit, */ - /* enable ADC high pass filter. Fixes bug 5323? */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26), - MAKE_WM8775_DATA(0x26)); - /* Set the master mode (256fs) */ if (1 == info->msr) { - /* slave mode, 128x oversampling 256fs */ hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02), MAKE_WM8775_DATA(0x02)); - } else if ((2 == info->msr) || (4 == info->msr)) { - /* slave mode, 64x oversampling, 256fs */ + } else if (2 == info->msr) { hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), MAKE_WM8775_DATA(0x0A)); } else { @@ -1896,113 +1818,55 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) goto error; } - if (hw->model != CTSB1270) { - /* Configure GPIO bit 14 change to line-in/mic-in */ - ctl = hw_read_20kx(hw, GPIO_CTRL); - ctl |= 0x1 << 14; - hw_write_20kx(hw, GPIO_CTRL, ctl); - hw_adc_input_select(hw, ADC_LINEIN); - } else { - hw_wm8775_input_select(hw, 0, 0); - } + /* Configure GPIO bit 14 change to line-in/mic-in */ + ctl = hw_read_20kx(hw, GPIO_CTRL); + ctl |= 0x1 << 14; + hw_write_20kx(hw, GPIO_CTRL, ctl); - return 0; -error: - hw20k2_i2c_uninit(hw); - return err; -} - -static struct capabilities hw_capabilities(struct hw *hw) -{ - struct capabilities cap; - - cap.digit_io_switch = 0; - cap.dedicated_mic = hw->model == CTSB1270; - cap.output_switch = hw->model == CTSB1270; - cap.mic_source_switch = hw->model == CTSB1270; - - return cap; -} - -static int hw_output_switch_get(struct hw *hw) -{ - u32 data = hw_read_20kx(hw, GPIO_EXT_DATA); - - switch (data & 0x30) { - case 0x00: - return 0; - case 0x10: - return 1; - case 0x20: - return 2; - default: - return 3; - } -} - -static int hw_output_switch_put(struct hw *hw, int position) -{ - u32 data; - - if (position == hw_output_switch_get(hw)) - return 0; - - /* Mute line and headphones (intended for anti-pop). */ + /* Check using Mic-in or Line-in */ data = hw_read_20kx(hw, GPIO_DATA); - data |= (0x03 << 11); - hw_write_20kx(hw, GPIO_DATA, data); - data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30; - switch (position) { - case 0: - break; - case 1: - data |= 0x10; - break; - default: - data |= 0x20; - } - hw_write_20kx(hw, GPIO_EXT_DATA, data); + if (mux == 1) { + /* Configures GPIO data to select Mic-in */ + data |= 0x1 << 14; + hw_write_20kx(hw, GPIO_DATA, data); - /* Unmute line and headphones. */ - data = hw_read_20kx(hw, GPIO_DATA); - data &= ~(0x03 << 11); - hw_write_20kx(hw, GPIO_DATA, data); + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), + MAKE_WM8775_DATA(0x101)); /* Mic-in */ + hw20k2_i2c_write(hw, + MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB), + MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ + hw20k2_i2c_write(hw, + MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB), + MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ + } else if (mux == 2) { + /* Configures GPIO data to select Line-in */ + data &= ~(0x1 << 14); + hw_write_20kx(hw, GPIO_DATA, data); - return 1; -} + /* Setup ADC */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), + MAKE_WM8775_DATA(0x102)); /* Line-in */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ + } else { + printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n"); + err = -EINVAL; + goto error; + } -static int hw_mic_source_switch_get(struct hw *hw) -{ - struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; + return 0; - return hw20k2->mic_source; +error: + hw20k2_i2c_uninit(hw); + return err; } -static int hw_mic_source_switch_put(struct hw *hw, int position) +static int hw_have_digit_io_switch(struct hw *hw) { - struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; - - if (position == hw20k2->mic_source) - return 0; - - switch (position) { - case 0: - hw_wm8775_input_select(hw, 0, 0); /* Mic, 0dB */ - break; - case 1: - hw_wm8775_input_select(hw, 1, 0); /* FP Mic, 0dB */ - break; - case 2: - hw_wm8775_input_select(hw, 3, 0); /* Aux Ext, 0dB */ - break; - default: - return 0; - } - - hw20k2->mic_source = position; - - return 1; + return 0; } static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id) @@ -2061,7 +1925,7 @@ static int hw_card_start(struct hw *hw) if (hw->irq < 0) { err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED, - KBUILD_MODNAME, hw); + "ctxfi", hw); if (err < 0) { printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); goto error2; @@ -2159,16 +2023,13 @@ static int hw_card_init(struct hw *hw, struct card_conf *info) /* Reset all SRC pending interrupts */ hw_write_20kx(hw, SRC_IP, 0); - if (hw->model != CTSB1270) { - /* TODO: detect the card ID and configure GPIO accordingly. */ - /* Configures GPIO (0xD802 0x98028) */ - /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/ - /* Configures GPIO (SB0880) */ - /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/ - hw_write_20kx(hw, GPIO_CTRL, 0xD802); - } else { - hw_write_20kx(hw, GPIO_CTRL, 0x9E5F); - } + /* TODO: detect the card ID and configure GPIO accordingly. */ + /* Configures GPIO (0xD802 0x98028) */ + /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/ + /* Configures GPIO (SB0880) */ + /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/ + hw_write_20kx(hw, GPIO_CTRL, 0xD802); + /* Enable audio ring */ hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01); @@ -2245,11 +2106,7 @@ static struct hw ct20k2_preset __devinitdata = { .pll_init = hw_pll_init, .is_adc_source_selected = hw_is_adc_input_selected, .select_adc_source = hw_adc_input_select, - .capabilities = hw_capabilities, - .output_switch_get = hw_output_switch_get, - .output_switch_put = hw_output_switch_put, - .mic_source_switch_get = hw_mic_source_switch_get, - .mic_source_switch_put = hw_mic_source_switch_put, + .have_digit_io_switch = hw_have_digit_io_switch, #ifdef CONFIG_PM .suspend = hw_suspend, .resume = hw_resume, diff --git a/trunk/sound/pci/ctxfi/ctmixer.c b/trunk/sound/pci/ctxfi/ctmixer.c index 0cc13eeef8da..c3519ff42fbb 100644 --- a/trunk/sound/pci/ctxfi/ctmixer.c +++ b/trunk/sound/pci/ctxfi/ctmixer.c @@ -86,7 +86,9 @@ enum CTALSA_MIXER_CTL { MIXER_LINEIN_C_S, MIXER_MIC_C_S, MIXER_SPDIFI_C_S, + MIXER_LINEIN_P_S, MIXER_SPDIFO_P_S, + MIXER_SPDIFI_P_S, MIXER_WAVEF_P_S, MIXER_WAVER_P_S, MIXER_WAVEC_P_S, @@ -135,11 +137,11 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { }, [MIXER_LINEIN_P] = { .ctl = 1, - .name = "Line Playback Volume", + .name = "Line-in Playback Volume", }, [MIXER_LINEIN_C] = { .ctl = 1, - .name = "Line Capture Volume", + .name = "Line-in Capture Volume", }, [MIXER_MIC_P] = { .ctl = 1, @@ -151,15 +153,15 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { }, [MIXER_SPDIFI_P] = { .ctl = 1, - .name = "IEC958 Playback Volume", + .name = "S/PDIF-in Playback Volume", }, [MIXER_SPDIFI_C] = { .ctl = 1, - .name = "IEC958 Capture Volume", + .name = "S/PDIF-in Capture Volume", }, [MIXER_SPDIFO_P] = { .ctl = 1, - .name = "Digital Playback Volume", + .name = "S/PDIF-out Playback Volume", }, [MIXER_WAVEF_P] = { .ctl = 1, @@ -177,13 +179,14 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { .ctl = 1, .name = "Surround Playback Volume", }, + [MIXER_PCM_C_S] = { .ctl = 1, .name = "PCM Capture Switch", }, [MIXER_LINEIN_C_S] = { .ctl = 1, - .name = "Line Capture Switch", + .name = "Line-in Capture Switch", }, [MIXER_MIC_C_S] = { .ctl = 1, @@ -191,11 +194,19 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { }, [MIXER_SPDIFI_C_S] = { .ctl = 1, - .name = "IEC958 Capture Switch", + .name = "S/PDIF-in Capture Switch", + }, + [MIXER_LINEIN_P_S] = { + .ctl = 1, + .name = "Line-in Playback Switch", }, [MIXER_SPDIFO_P_S] = { .ctl = 1, - .name = "Digital Playback Switch", + .name = "S/PDIF-out Playback Switch", + }, + [MIXER_SPDIFI_P_S] = { + .ctl = 1, + .name = "S/PDIF-in Playback Switch", }, [MIXER_WAVEF_P_S] = { .ctl = 1, @@ -225,8 +236,6 @@ ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); static void ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); -/* FIXME: this static looks like it would fail if more than one card was */ -/* installed. */ static struct snd_kcontrol *kctls[2] = {NULL}; static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index) @@ -411,77 +420,6 @@ static struct snd_kcontrol_new vol_ctl = { .tlv = { .p = ct_vol_db_scale }, }; -static int output_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *info) -{ - static const char *const names[3] = { - "FP Headphones", "Headphones", "Speakers" - }; - - return snd_ctl_enum_info(info, 1, 3, names); -} - -static int output_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc); - return 0; -} - -static int output_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - if (ucontrol->value.enumerated.item[0] > 2) - return -EINVAL; - return atc->output_switch_put(atc, ucontrol->value.enumerated.item[0]); -} - -static struct snd_kcontrol_new output_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Output Playback Enum", - .info = output_switch_info, - .get = output_switch_get, - .put = output_switch_put, -}; - -static int mic_source_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *info) -{ - static const char *const names[3] = { - "Mic", "FP Mic", "Aux" - }; - - return snd_ctl_enum_info(info, 1, 3, names); -} - -static int mic_source_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc); - return 0; -} - -static int mic_source_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - if (ucontrol->value.enumerated.item[0] > 2) - return -EINVAL; - return atc->mic_source_switch_put(atc, - ucontrol->value.enumerated.item[0]); -} - -static struct snd_kcontrol_new mic_source_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic Source Capture Enum", - .info = mic_source_switch_info, - .get = mic_source_switch_get, - .put = mic_source_switch_put, -}; - static void do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type) { @@ -527,7 +465,6 @@ do_digit_io_switch(struct ct_atc *atc, int state) static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) { struct ct_mixer *mixer = atc->mixer; - struct capabilities cap = atc->capabilities(atc); /* Do changes in mixer. */ if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) { @@ -540,17 +477,8 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) } } /* Do changes out of mixer. */ - if (!cap.dedicated_mic && - (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) { - if (state) - do_line_mic_switch(atc, type); - atc->line_in_unmute(atc, state); - } else if (cap.dedicated_mic && (MIXER_LINEIN_C_S == type)) - atc->line_in_unmute(atc, state); - else if (cap.dedicated_mic && (MIXER_MIC_C_S == type)) - atc->mic_unmute(atc, state); - else if (MIXER_SPDIFI_C_S == type) - atc->spdif_in_unmute(atc, state); + if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) + do_line_mic_switch(atc, type); else if (MIXER_WAVEF_P_S == type) atc->line_front_unmute(atc, state); else if (MIXER_WAVES_P_S == type) @@ -559,8 +487,12 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) atc->line_clfe_unmute(atc, state); else if (MIXER_WAVER_P_S == type) atc->line_rear_unmute(atc, state); + else if (MIXER_LINEIN_P_S == type) + atc->line_in_unmute(atc, state); else if (MIXER_SPDIFO_P_S == type) atc->spdif_out_unmute(atc, state); + else if (MIXER_SPDIFI_P_S == type) + atc->spdif_in_unmute(atc, state); else if (MIXER_DIGITAL_IO_S == type) do_digit_io_switch(atc, state); @@ -739,7 +671,6 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) { enum CTALSA_MIXER_CTL type; struct ct_atc *atc = mixer->atc; - struct capabilities cap = atc->capabilities(atc); int err; /* Create snd kcontrol instances on demand */ @@ -753,8 +684,8 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) } } - ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = cap.digit_io_switch; - + ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = + atc->have_digit_io_switch(atc); for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) { if (ct_kcontrol_init_table[type].ctl) { swh_ctl.name = ct_kcontrol_init_table[type].name; @@ -777,17 +708,6 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) if (err) return err; - if (cap.output_switch) { - err = ct_mixer_kcontrol_new(mixer, &output_ctl); - if (err) - return err; - } - - if (cap.mic_source_switch) { - err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl); - if (err) - return err; - } atc->line_front_unmute(atc, 1); set_switch_state(mixer, MIXER_WAVEF_P_S, 1); atc->line_surround_unmute(atc, 0); @@ -799,12 +719,13 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) atc->spdif_out_unmute(atc, 0); set_switch_state(mixer, MIXER_SPDIFO_P_S, 0); atc->line_in_unmute(atc, 0); - if (cap.dedicated_mic) - atc->mic_unmute(atc, 0); + set_switch_state(mixer, MIXER_LINEIN_P_S, 0); atc->spdif_in_unmute(atc, 0); - set_switch_state(mixer, MIXER_PCM_C_S, 0); - set_switch_state(mixer, MIXER_LINEIN_C_S, 0); - set_switch_state(mixer, MIXER_SPDIFI_C_S, 0); + set_switch_state(mixer, MIXER_SPDIFI_P_S, 0); + + set_switch_state(mixer, MIXER_PCM_C_S, 1); + set_switch_state(mixer, MIXER_LINEIN_C_S, 1); + set_switch_state(mixer, MIXER_SPDIFI_C_S, 1); return 0; } diff --git a/trunk/sound/pci/ctxfi/xfi.c b/trunk/sound/pci/ctxfi/xfi.c index b259aa03a3a9..f42e7e1a1074 100644 --- a/trunk/sound/pci/ctxfi/xfi.c +++ b/trunk/sound/pci/ctxfi/xfi.c @@ -80,11 +80,11 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) "are 48000 and 44100, Value 48000 is assumed.\n"); reference_rate = 48000; } - if ((multiple != 1) && (multiple != 2) && (multiple != 4)) { + if ((multiple != 1) && (multiple != 2)) { printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n", multiple); printk(KERN_ERR "ctxfi: The valid values for multiple are " - "1, 2 and 4, Value 2 is assumed.\n"); + "1 and 2, Value 2 is assumed.\n"); multiple = 2; } err = ct_atc_create(card, pci, reference_rate, multiple, @@ -143,7 +143,7 @@ static int ct_card_resume(struct pci_dev *pci) #endif static struct pci_driver ct_driver = { - .name = KBUILD_MODNAME, + .name = "SB-XFi", .id_table = ct_pci_dev_ids, .probe = ct_card_probe, .remove = __devexit_p(ct_card_remove), diff --git a/trunk/sound/pci/echoaudio/echoaudio.c b/trunk/sound/pci/echoaudio/echoaudio.c index d7306980d0f1..20763dd03fa0 100644 --- a/trunk/sound/pci/echoaudio/echoaudio.c +++ b/trunk/sound/pci/echoaudio/echoaudio.c @@ -1995,7 +1995,7 @@ static __devinit int snd_echo_create(struct snd_card *card, ioremap_nocache(chip->dsp_registers_phys, sz); if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + ECHOCARD_NAME, chip)) { snd_echo_free(chip); snd_printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; @@ -2286,7 +2286,7 @@ static int snd_echo_resume(struct pci_dev *pci) kfree(commpage_bak); if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + ECHOCARD_NAME, chip)) { snd_echo_free(chip); snd_printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; @@ -2327,7 +2327,7 @@ static void __devexit snd_echo_remove(struct pci_dev *pci) /* pci_driver definition */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Echoaudio " ECHOCARD_NAME, .id_table = snd_echo_ids, .probe = snd_echo_probe, .remove = __devexit_p(snd_echo_remove), diff --git a/trunk/sound/pci/emu10k1/emu10k1.c b/trunk/sound/pci/emu10k1/emu10k1.c index a9c45d2cdb13..aff8387c45cf 100644 --- a/trunk/sound/pci/emu10k1/emu10k1.c +++ b/trunk/sound/pci/emu10k1/emu10k1.c @@ -264,7 +264,7 @@ static int snd_emu10k1_resume(struct pci_dev *pci) #endif static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "EMU10K1_Audigy", .id_table = snd_emu10k1_ids, .probe = snd_card_emu10k1_probe, .remove = __devexit_p(snd_card_emu10k1_remove), diff --git a/trunk/sound/pci/emu10k1/emu10k1_main.c b/trunk/sound/pci/emu10k1/emu10k1_main.c index fcd4935766b2..15f0161ce4a2 100644 --- a/trunk/sound/pci/emu10k1/emu10k1_main.c +++ b/trunk/sound/pci/emu10k1/emu10k1_main.c @@ -1912,7 +1912,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card, /* irq handler must be registered after I/O ports are activated */ if (request_irq(pci->irq, snd_emu10k1_interrupt, IRQF_SHARED, - KBUILD_MODNAME, emu)) { + "EMU10K1", emu)) { err = -EBUSY; goto error; } diff --git a/trunk/sound/pci/emu10k1/emu10k1x.c b/trunk/sound/pci/emu10k1/emu10k1x.c index d4fde1b4b093..0c701e4ec8a5 100644 --- a/trunk/sound/pci/emu10k1/emu10k1x.c +++ b/trunk/sound/pci/emu10k1/emu10k1x.c @@ -925,7 +925,7 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card, } if (request_irq(pci->irq, snd_emu10k1x_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "EMU10K1X", chip)) { snd_printk(KERN_ERR "emu10k1x: cannot grab irq %d\n", pci->irq); snd_emu10k1x_free(chip); return -EBUSY; @@ -1613,7 +1613,7 @@ MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids); // pci_driver definition static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "EMU10K1X", .id_table = snd_emu10k1x_ids, .probe = snd_emu10k1x_probe, .remove = __devexit_p(snd_emu10k1x_remove), diff --git a/trunk/sound/pci/ens1370.c b/trunk/sound/pci/ens1370.c index f02e2f8d7122..863eafea691f 100644 --- a/trunk/sound/pci/ens1370.c +++ b/trunk/sound/pci/ens1370.c @@ -2120,7 +2120,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, } ensoniq->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_audiopci_interrupt, IRQF_SHARED, - KBUILD_MODNAME, ensoniq)) { + "Ensoniq AudioPCI", ensoniq)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_ensoniq_free(ensoniq); return -EBUSY; @@ -2489,7 +2489,7 @@ static void __devexit snd_audiopci_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = DRIVER_NAME, .id_table = snd_audiopci_ids, .probe = snd_audiopci_probe, .remove = __devexit_p(snd_audiopci_remove), diff --git a/trunk/sound/pci/es1938.c b/trunk/sound/pci/es1938.c index 26a5a2f25d4b..553b75217259 100644 --- a/trunk/sound/pci/es1938.c +++ b/trunk/sound/pci/es1938.c @@ -1514,7 +1514,7 @@ static int es1938_resume(struct pci_dev *pci) } if (request_irq(pci->irq, snd_es1938_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, "ES1938", chip)) { printk(KERN_ERR "es1938: unable to grab IRQ %d, " "disabling device\n", pci->irq); snd_card_disconnect(card); @@ -1636,7 +1636,7 @@ static int __devinit snd_es1938_create(struct snd_card *card, chip->mpu_port = pci_resource_start(pci, 3); chip->game_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "ES1938", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_es1938_free(chip); return -EBUSY; @@ -1882,7 +1882,7 @@ static void __devexit snd_es1938_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ESS ES1938 (Solo-1)", .id_table = snd_es1938_ids, .probe = snd_es1938_probe, .remove = __devexit_p(snd_es1938_remove), diff --git a/trunk/sound/pci/es1968.c b/trunk/sound/pci/es1968.c index 99ea9320c6b5..ab0a6156a704 100644 --- a/trunk/sound/pci/es1968.c +++ b/trunk/sound/pci/es1968.c @@ -554,8 +554,9 @@ struct es1968 { #else struct snd_kcontrol *master_switch; /* for h/w volume control */ struct snd_kcontrol *master_volume; + spinlock_t ac97_lock; + struct tasklet_struct hwvol_tq; #endif - struct work_struct hwvol_work; #ifdef CONFIG_SND_ES1968_RADIO struct snd_tea575x tea; @@ -645,23 +646,38 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip) static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct es1968 *chip = ac97->private_data; +#ifndef CONFIG_SND_ES1968_INPUT + unsigned long flags; +#endif snd_es1968_ac97_wait(chip); /* Write the bus */ +#ifndef CONFIG_SND_ES1968_INPUT + spin_lock_irqsave(&chip->ac97_lock, flags); +#endif outw(val, chip->io_port + ESM_AC97_DATA); /*msleep(1);*/ outb(reg, chip->io_port + ESM_AC97_INDEX); /*msleep(1);*/ +#ifndef CONFIG_SND_ES1968_INPUT + spin_unlock_irqrestore(&chip->ac97_lock, flags); +#endif } static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { u16 data = 0; struct es1968 *chip = ac97->private_data; +#ifndef CONFIG_SND_ES1968_INPUT + unsigned long flags; +#endif snd_es1968_ac97_wait(chip); +#ifndef CONFIG_SND_ES1968_INPUT + spin_lock_irqsave(&chip->ac97_lock, flags); +#endif outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX); /*msleep(1);*/ @@ -669,6 +685,9 @@ static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short data = inw(chip->io_port + ESM_AC97_DATA); /*msleep(1);*/ } +#ifndef CONFIG_SND_ES1968_INPUT + spin_unlock_irqrestore(&chip->ac97_lock, flags); +#endif return data; } @@ -1885,10 +1904,13 @@ static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es) (without wrap around) in response to volume button presses and then generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 of a byte wide register. The meaning of bits 0 and 4 is unknown. */ -static void es1968_update_hw_volume(struct work_struct *work) +static void es1968_update_hw_volume(unsigned long private_data) { - struct es1968 *chip = container_of(work, struct es1968, hwvol_work); + struct es1968 *chip = (struct es1968 *) private_data; int x, val; +#ifndef CONFIG_SND_ES1968_INPUT + unsigned long flags; +#endif /* Figure out which volume control button was pushed, based on differences from the default register @@ -1907,11 +1929,18 @@ static void es1968_update_hw_volume(struct work_struct *work) if (! chip->master_switch || ! chip->master_volume) return; - val = snd_ac97_read(chip->ac97, AC97_MASTER); + /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ + spin_lock_irqsave(&chip->ac97_lock, flags); + val = chip->ac97->regs[AC97_MASTER]; switch (x) { case 0x88: /* mute */ val ^= 0x8000; + chip->ac97->regs[AC97_MASTER] = val; + outw(val, chip->io_port + ESM_AC97_DATA); + outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_switch->id); break; case 0xaa: /* volume up */ @@ -1919,6 +1948,11 @@ static void es1968_update_hw_volume(struct work_struct *work) val--; if ((val & 0x7f00) > 0) val -= 0x0100; + chip->ac97->regs[AC97_MASTER] = val; + outw(val, chip->io_port + ESM_AC97_DATA); + outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); break; case 0x66: /* volume down */ @@ -1926,11 +1960,14 @@ static void es1968_update_hw_volume(struct work_struct *work) val++; if ((val & 0x7f00) < 0x1f00) val += 0x0100; - break; - } - if (snd_ac97_update(chip->ac97, AC97_MASTER, val)) + chip->ac97->regs[AC97_MASTER] = val; + outw(val, chip->io_port + ESM_AC97_DATA); + outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); + break; + } + spin_unlock_irqrestore(&chip->ac97_lock, flags); #else if (!chip->input_dev) return; @@ -1976,7 +2013,11 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); if (event & ESM_HWVOL_IRQ) - schedule_work(&chip->hwvol_work); +#ifdef CONFIG_SND_ES1968_INPUT + es1968_update_hw_volume((unsigned long)chip); +#else + tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */ +#endif /* else ack 'em all, i imagine */ outb(0xFF, chip->io_port + 0x1A); @@ -2385,7 +2426,6 @@ static int es1968_suspend(struct pci_dev *pci, pm_message_t state) return 0; chip->in_suspend = 1; - cancel_work_sync(&chip->hwvol_work); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); @@ -2598,7 +2638,6 @@ static struct snd_tea575x_ops snd_es1968_tea_ops = { static int snd_es1968_free(struct es1968 *chip) { - cancel_work_sync(&chip->hwvol_work); #ifdef CONFIG_SND_ES1968_INPUT if (chip->input_dev) input_unregister_device(chip->input_dev); @@ -2689,7 +2728,10 @@ static int __devinit snd_es1968_create(struct snd_card *card, INIT_LIST_HEAD(&chip->buf_list); INIT_LIST_HEAD(&chip->substream_list); mutex_init(&chip->memory_mutex); - INIT_WORK(&chip->hwvol_work, es1968_update_hw_volume); +#ifndef CONFIG_SND_ES1968_INPUT + spin_lock_init(&chip->ac97_lock); + tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip); +#endif chip->card = card; chip->pci = pci; chip->irq = -1; @@ -2704,7 +2746,7 @@ static int __devinit snd_es1968_create(struct snd_card *card, } chip->io_port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "ESS Maestro", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_es1968_free(chip); return -EBUSY; @@ -2883,7 +2925,7 @@ static void __devexit snd_es1968_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ES1968 (ESS Maestro)", .id_table = snd_es1968_ids, .probe = snd_es1968_probe, .remove = __devexit_p(snd_es1968_remove), diff --git a/trunk/sound/pci/fm801.c b/trunk/sound/pci/fm801.c index f9123f09e83e..a7ec7030cf87 100644 --- a/trunk/sound/pci/fm801.c +++ b/trunk/sound/pci/fm801.c @@ -1199,7 +1199,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, chip->port = pci_resource_start(pci, 0); if ((tea575x_tuner & TUNER_ONLY) == 0) { if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "FM801", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); snd_fm801_free(chip); return -EBUSY; @@ -1394,7 +1394,7 @@ static int snd_fm801_resume(struct pci_dev *pci) #endif static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "FM801", .id_table = snd_fm801_ids, .probe = snd_card_fm801_probe, .remove = __devexit_p(snd_card_fm801_remove), diff --git a/trunk/sound/pci/hda/Kconfig b/trunk/sound/pci/hda/Kconfig index 7489b4608551..0ea5cc60ac78 100644 --- a/trunk/sound/pci/hda/Kconfig +++ b/trunk/sound/pci/hda/Kconfig @@ -14,19 +14,6 @@ menuconfig SND_HDA_INTEL if SND_HDA_INTEL -config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" - range 0 32768 - default 64 - help - Specifies the default pre-allocated buffer-size in kB for the - HD-audio driver. A larger buffer (e.g. 2048) is preferred - for systems using PulseAudio. The default 64 is chosen just - for compatibility reasons. - - Note that the pre-allocation size can be changed dynamically - via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. - config SND_HDA_HWDEP bool "Build hwdep interface for HD-audio driver" select SND_HWDEP @@ -96,19 +83,6 @@ config SND_HDA_CODEC_REALTEK snd-hda-codec-realtek. This module is automatically loaded at probing. -config SND_HDA_ENABLE_REALTEK_QUIRKS - bool "Build static quirks for Realtek codecs" - depends on SND_HDA_CODEC_REALTEK - default y - help - Say Y here to build the static quirks codes for Realtek codecs. - If you need the "model" preset that the default BIOS auto-parser - can't handle, turn this option on. - - If your device works with model=auto option, basically you don't - need the quirk code. By turning this off, you can reduce the - module size quite a lot. - config SND_HDA_CODEC_ANALOG bool "Build Analog Device HD-audio codec support" default y @@ -197,19 +171,6 @@ config SND_HDA_CODEC_CA0110 snd-hda-codec-ca0110. This module is automatically loaded at probing. -config SND_HDA_CODEC_CA0132 - bool "Build Creative CA0132 codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Creative CA0132 codec support in - snd-hda-intel driver. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-ca0132. - This module is automatically loaded at probing. - config SND_HDA_CODEC_CMEDIA bool "Build C-Media HD-audio codec support" default y diff --git a/trunk/sound/pci/hda/Makefile b/trunk/sound/pci/hda/Makefile index 87365d5ea2a9..17ef3658f34b 100644 --- a/trunk/sound/pci/hda/Makefile +++ b/trunk/sound/pci/hda/Makefile @@ -13,7 +13,6 @@ snd-hda-codec-idt-objs := patch_sigmatel.o snd-hda-codec-si3054-objs := patch_si3054.o snd-hda-codec-cirrus-objs := patch_cirrus.o snd-hda-codec-ca0110-objs := patch_ca0110.o -snd-hda-codec-ca0132-objs := patch_ca0132.o snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-via-objs := patch_via.o snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o @@ -43,9 +42,6 @@ endif ifdef CONFIG_SND_HDA_CODEC_CA0110 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o endif -ifdef CONFIG_SND_HDA_CODEC_CA0132 -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0132.o -endif ifdef CONFIG_SND_HDA_CODEC_CONEXANT obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o endif diff --git a/trunk/sound/pci/hda/alc260_quirks.c b/trunk/sound/pci/hda/alc260_quirks.c deleted file mode 100644 index 21ec2cb100b0..000000000000 --- a/trunk/sound/pci/hda/alc260_quirks.c +++ /dev/null @@ -1,1272 +0,0 @@ -/* - * ALC260 quirk models - * included by patch_realtek.c - */ - -/* ALC260 models */ -enum { - ALC260_AUTO, - ALC260_BASIC, - ALC260_HP, - ALC260_HP_DC7600, - ALC260_HP_3013, - ALC260_FUJITSU_S702X, - ALC260_ACER, - ALC260_WILL, - ALC260_REPLACER_672V, - ALC260_FAVORIT100, -#ifdef CONFIG_SND_DEBUG - ALC260_TEST, -#endif - ALC260_MODEL_LAST /* last tag */ -}; - -static const hda_nid_t alc260_dac_nids[1] = { - /* front */ - 0x02, -}; - -static const hda_nid_t alc260_adc_nids[1] = { - /* ADC0 */ - 0x04, -}; - -static const hda_nid_t alc260_adc_nids_alt[1] = { - /* ADC1 */ - 0x05, -}; - -/* NIDs used when simultaneous access to both ADCs makes sense. Note that - * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. - */ -static const hda_nid_t alc260_dual_adc_nids[2] = { - /* ADC0, ADC1 */ - 0x04, 0x05 -}; - -#define ALC260_DIGOUT_NID 0x03 -#define ALC260_DIGIN_NID 0x06 - -static const struct hda_input_mux alc260_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack, - * headphone jack and the internal CD lines since these are the only pins at - * which audio can appear. For flexibility, also allow the option of - * recording the mixer output on the second ADC (ADC0 doesn't have a - * connection to the mixer output). - */ -static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = { - { - .num_items = 3, - .items = { - { "Mic/Line", 0x0 }, - { "CD", 0x4 }, - { "Headphone", 0x2 }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic/Line", 0x0 }, - { "CD", 0x4 }, - { "Headphone", 0x2 }, - { "Mixer", 0x5 }, - }, - }, - -}; - -/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to - * the Fujitsu S702x, but jacks are marked differently. - */ -static const struct hda_input_mux alc260_acer_capture_sources[2] = { - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Headphone", 0x5 }, - }, - }, - { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Headphone", 0x6 }, - { "Mixer", 0x5 }, - }, - }, -}; - -/* Maxdata Favorit 100XS */ -static const struct hda_input_mux alc260_favorit100_capture_sources[2] = { - { - .num_items = 2, - .items = { - { "Line/Mic", 0x0 }, - { "CD", 0x4 }, - }, - }, - { - .num_items = 3, - .items = { - { "Line/Mic", 0x0 }, - { "CD", 0x4 }, - { "Mixer", 0x5 }, - }, - }, -}; - -/* - * This is just place-holder, so there's something for alc_build_pcms to look - * at when it calculates the maximum number of channels. ALC260 has no mixer - * element which allows changing the channel mode, so the verb list is - * never used. - */ -static const struct hda_channel_mode alc260_modes[1] = { - { 2, NULL }, -}; - - -/* Mixer combinations - * - * basic: base_output + input + pc_beep + capture - * HP: base_output + input + capture_alt - * HP_3013: hp_3013 + input + capture - * fujitsu: fujitsu + capture - * acer: acer + capture - */ - -static const struct snd_kcontrol_new alc260_base_output_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc260_input_mixer[] = { - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), - { } /* end */ -}; - -/* update HP, line and mono out pins according to the master switch */ -static void alc260_hp_master_update(struct hda_codec *codec) -{ - update_speakers(codec); -} - -static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - *ucontrol->value.integer.value = !spec->master_mute; - return 0; -} - -static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int val = !*ucontrol->value.integer.value; - - if (val == spec->master_mute) - return 0; - spec->master_mute = val; - alc260_hp_master_update(codec); - return 1; -} - -static const struct snd_kcontrol_new alc260_hp_output_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, - .info = snd_ctl_boolean_mono_info, - .get = alc260_hp_master_sw_get, - .put = alc260_hp_master_sw_put, - }, - HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc260_hp_unsol_verbs[] = { - {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {}, -}; - -static void alc260_hp_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x0f; - spec->autocfg.speaker_pins[0] = 0x10; - spec->autocfg.speaker_pins[1] = 0x11; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, - .info = snd_ctl_boolean_mono_info, - .get = alc260_hp_master_sw_get, - .put = alc260_hp_master_sw_put, - }, - HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static void alc260_hp_3013_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x10; - spec->autocfg.speaker_pins[1] = 0x11; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc260_dc7600_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol), - HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct hda_verb alc260_hp_3013_unsol_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {}, -}; - -static void alc260_hp_3012_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x10; - spec->autocfg.speaker_pins[0] = 0x0f; - spec->autocfg.speaker_pins[1] = 0x11; - spec->autocfg.speaker_pins[2] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, - * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. - */ -static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), - ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT), - { } /* end */ -}; - -/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current - * versions of the ALC260 don't act on requests to enable mic bias from NID - * 0x0f (used to drive the headphone jack in these laptops). The ALC260 - * datasheet doesn't mention this restriction. At this stage it's not clear - * whether this behaviour is intentional or is a hardware bug in chip - * revisions available in early 2006. Therefore for now allow the - * "Headphone Jack Mode" control to span all choices, but if it turns out - * that the lack of mic bias for this NID is intentional we could change the - * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. - * - * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006 - * don't appear to make the mic bias available from the "line" jack, even - * though the NID used for this jack (0x14) can supply it. The theory is - * that perhaps Acer have included blocking capacitors between the ALC260 - * and the output jack. If this turns out to be the case for all such - * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT - * to ALC_PIN_DIR_INOUT_NOMICBIAS. - * - * The C20x Tablet series have a mono internal speaker which is controlled - * via the chip's Mono sum widget and pin complex, so include the necessary - * controls for such models. On models without a "mono speaker" the control - * won't do anything. - */ -static const struct snd_kcontrol_new alc260_acer_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), - ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, - HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - { } /* end */ -}; - -/* Maxdata Favorit 100XS: one output and one input (0x12) jack - */ -static const struct snd_kcontrol_new alc260_favorit100_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), - ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - { } /* end */ -}; - -/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12, - * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17. - */ -static const struct snd_kcontrol_new alc260_will_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - { } /* end */ -}; - -/* Replacer 672V ALC260 pin usage: Mic jack = 0x12, - * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f. - */ -static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - { } /* end */ -}; - -/* - * initialization verbs - */ -static const struct hda_verb alc260_init_verbs[] = { - /* Line In pin widget for input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* CD pin widget for input */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* LINE-2 is used for line-out in rear */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* select line-out */ - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LINE-OUT pin */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* enable HP */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* enable Mono */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to line in (default select for this ADC) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* mute capture amp left and right */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to line in (default select for this ADC) */ - {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* set vol=0 Line-Out mixer amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 HP mixer amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 Mono mixer amp left and right */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* unmute LINE-2 out pin */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & - * Line In 2 = 0x03 - */ - /* mute analog inputs */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* mute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* mute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* mute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } -}; - -#if 0 /* should be identical with alc260_init_verbs? */ -static const struct hda_verb alc260_hp_init_verbs[] = { - /* Headphone and output */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - /* mono output */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Line In pin widget for input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* Line-2 pin widget for output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* CD pin widget for input */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* unmute amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* unmute Line-Out mixer amp left and right (volume = 0) */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute HP mixer amp left and right (volume = 0) */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & - * Line In 2 = 0x03 - */ - /* mute analog inputs */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - { } -}; -#endif - -static const struct hda_verb alc260_hp_3013_init_verbs[] = { - /* Line out and output */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* mono output */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Line In pin widget for input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* Headphone pin widget for output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - /* CD pin widget for input */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* unmute amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* unmute Line-Out mixer amp left and right (volume = 0) */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute HP mixer amp left and right (volume = 0) */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & - * Line In 2 = 0x03 - */ - /* mute analog inputs */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - { } -}; - -/* Initialisation sequence for ALC260 as configured in Fujitsu S702x - * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD - * audio = 0x16, internal speaker = 0x10. - */ -static const struct hda_verb alc260_fujitsu_init_verbs[] = { - /* Disable all GPIOs */ - {0x01, AC_VERB_SET_GPIO_MASK, 0}, - /* Internal speaker is connected to headphone pin */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Headphone/Line-out jack connects to Line1 pin; make it an output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Ensure all other unused pins are disabled and muted. */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Line1 pin widget takes its input from the OUT1 sum bus - * when acting as an output. - */ - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Line1 pin widget output buffer since it starts as an output. - * If the pin mode is changed by the user the pin mode control will - * take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute input buffer of pin widget used for Line-in (no equiv - * mixer ctrl) - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - line - * in (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do the same for the second ADC: mute capture input amp and - * set ADC connection to line in (on mic1 pin) - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -/* Initialisation sequence for ALC260 as configured in Acer TravelMate and - * similar laptops (adapted from Fujitsu init verbs). - */ -static const struct hda_verb alc260_acer_init_verbs[] = { - /* On TravelMate laptops, GPIO 0 enables the internal speaker and - * the headphone jack. Turn this on and rely on the standard mute - * methods whenever the user wants to turn these outputs off. - */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - /* Internal speaker/Headphone jack is connected to Line-out pin */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Internal microphone/Mic jack is connected to Mic1 pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - /* Line In jack is connected to Line1 pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Ensure all other unused pins are disabled and muted. */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum - * bus when acting as outputs. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute Line-out pin widget amp left and right - * (no equiv mixer ctrl) - */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute mono pin widget amp output (no equiv mixer ctrl) */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mic1 and Line1 pin widget input buffers since they start as - * inputs. If the pin mode is changed by the user the pin mode control - * will take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - mic - * (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do similar with the second ADC: mute capture input amp and - * set ADC connection to mic to match ALSA's default state. - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -/* Initialisation sequence for Maxdata Favorit 100XS - * (adapted from Acer init verbs). - */ -static const struct hda_verb alc260_favorit100_init_verbs[] = { - /* GPIO 0 enables the output jack. - * Turn this on and rely on the standard mute - * methods whenever the user wants to turn these outputs off. - */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - /* Line/Mic input jack is connected to Mic1 pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - /* Ensure all other unused pins are disabled and muted. */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum - * bus when acting as outputs. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute Line-out pin widget amp left and right - * (no equiv mixer ctrl) - */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mic1 and Line1 pin widget input buffers since they start as - * inputs. If the pin mode is changed by the user the pin mode control - * will take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - mic - * (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do similar with the second ADC: mute capture input amp and - * set ADC connection to mic to match ALSA's default state. - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -static const struct hda_verb alc260_will_verbs[] = { - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x1a, AC_VERB_SET_PROC_COEF, 0x3040}, - {} -}; - -static const struct hda_verb alc260_replacer_672v_verbs[] = { - {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x1a, AC_VERB_SET_PROC_COEF, 0x3050}, - - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - - {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc260_replacer_672v_automute(struct hda_codec *codec) -{ - unsigned int present; - - /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */ - present = snd_hda_jack_detect(codec, 0x0f); - if (present) { - snd_hda_codec_write_cache(codec, 0x01, 0, - AC_VERB_SET_GPIO_DATA, 1); - snd_hda_codec_write_cache(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_HP); - } else { - snd_hda_codec_write_cache(codec, 0x01, 0, - AC_VERB_SET_GPIO_DATA, 0); - snd_hda_codec_write_cache(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_OUT); - } -} - -static void alc260_replacer_672v_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc260_replacer_672v_automute(codec); -} - -static const struct hda_verb alc260_hp_dc7600_verbs[] = { - {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* Test configuration for debugging, modelled after the ALC880 test - * configuration. - */ -#ifdef CONFIG_SND_DEBUG -static const hda_nid_t alc260_test_dac_nids[1] = { - 0x02, -}; -static const hda_nid_t alc260_test_adc_nids[2] = { - 0x04, 0x05, -}; -/* For testing the ALC260, each input MUX needs its own definition since - * the signal assignments are different. This assumes that the first ADC - * is NID 0x04. - */ -static const struct hda_input_mux alc260_test_capture_sources[2] = { - { - .num_items = 7, - .items = { - { "MIC1 pin", 0x0 }, - { "MIC2 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "LINE2 pin", 0x3 }, - { "CD pin", 0x4 }, - { "LINE-OUT pin", 0x5 }, - { "HP-OUT pin", 0x6 }, - }, - }, - { - .num_items = 8, - .items = { - { "MIC1 pin", 0x0 }, - { "MIC2 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "LINE2 pin", 0x3 }, - { "CD pin", 0x4 }, - { "Mixer", 0x5 }, - { "LINE-OUT pin", 0x6 }, - { "HP-OUT pin", 0x7 }, - }, - }, -}; -static const struct snd_kcontrol_new alc260_test_mixer[] = { - /* Output driver widgets */ - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), - HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT), - HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT), - - /* Modes for retasking pin widgets - * Note: the ALC260 doesn't seem to act on requests to enable mic - * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't - * mention this restriction. At this stage it's not clear whether - * this behaviour is intentional or is a hardware bug in chip - * revisions available at least up until early 2006. Therefore for - * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all - * choices, but if it turns out that the lack of mic bias for these - * NIDs is intentional we could change their modes from - * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. - */ - ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT), - - /* Loopback mixer controls */ - HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT), - HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT), - - /* Controls for GPIO pins, assuming they are configured as outputs */ - ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), - ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), - ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), - ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), - - /* Switches to allow the digital IO pins to be enabled. The datasheet - * is ambigious as to which NID is which; testing on laptops which - * make this output available should provide clarification. - */ - ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), - ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), - - /* A switch allowing EAPD to be enabled. Some laptops seem to use - * this output to turn on an external amplifier. - */ - ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), - ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), - - { } /* end */ -}; -static const struct hda_verb alc260_test_init_verbs[] = { - /* Enable all GPIOs as outputs with an initial value of 0 */ - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, - - /* Enable retasking pins as output, initially without power amp */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the - * OUT1 sum bus when acting as an output. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0c, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Also unmute the mono-out pin widget */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do the same for the second ADC: mute capture input amp and - * set ADC connection to mic1 pin - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; -#endif - -/* - * ALC260 configurations - */ -static const char * const alc260_models[ALC260_MODEL_LAST] = { - [ALC260_BASIC] = "basic", - [ALC260_HP] = "hp", - [ALC260_HP_3013] = "hp-3013", - [ALC260_HP_DC7600] = "hp-dc7600", - [ALC260_FUJITSU_S702X] = "fujitsu", - [ALC260_ACER] = "acer", - [ALC260_WILL] = "will", - [ALC260_REPLACER_672V] = "replacer", - [ALC260_FAVORIT100] = "favorit100", -#ifdef CONFIG_SND_DEBUG - [ALC260_TEST] = "test", -#endif - [ALC260_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc260_cfg_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), - SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), - SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), - SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), - SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */ - SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), - SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), - SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP), - SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP), - SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), - SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), - SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), - SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), - {} -}; - -static const struct alc_config_preset alc260_presets[] = { - [ALC260_BASIC] = { - .mixers = { alc260_base_output_mixer, - alc260_input_mixer }, - .init_verbs = { alc260_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - }, - [ALC260_HP] = { - .mixers = { alc260_hp_output_mixer, - alc260_input_mixer }, - .init_verbs = { alc260_init_verbs, - alc260_hp_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), - .adc_nids = alc260_adc_nids_alt, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc260_hp_setup, - .init_hook = alc_inithook, - }, - [ALC260_HP_DC7600] = { - .mixers = { alc260_hp_dc7600_mixer, - alc260_input_mixer }, - .init_verbs = { alc260_init_verbs, - alc260_hp_dc7600_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), - .adc_nids = alc260_adc_nids_alt, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc260_hp_3012_setup, - .init_hook = alc_inithook, - }, - [ALC260_HP_3013] = { - .mixers = { alc260_hp_3013_mixer, - alc260_input_mixer }, - .init_verbs = { alc260_hp_3013_init_verbs, - alc260_hp_3013_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), - .adc_nids = alc260_adc_nids_alt, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc260_hp_3013_setup, - .init_hook = alc_inithook, - }, - [ALC260_FUJITSU_S702X] = { - .mixers = { alc260_fujitsu_mixer }, - .init_verbs = { alc260_fujitsu_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources), - .input_mux = alc260_fujitsu_capture_sources, - }, - [ALC260_ACER] = { - .mixers = { alc260_acer_mixer }, - .init_verbs = { alc260_acer_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), - .input_mux = alc260_acer_capture_sources, - }, - [ALC260_FAVORIT100] = { - .mixers = { alc260_favorit100_mixer }, - .init_verbs = { alc260_favorit100_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources), - .input_mux = alc260_favorit100_capture_sources, - }, - [ALC260_WILL] = { - .mixers = { alc260_will_mixer }, - .init_verbs = { alc260_init_verbs, alc260_will_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), - .adc_nids = alc260_adc_nids, - .dig_out_nid = ALC260_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - }, - [ALC260_REPLACER_672V] = { - .mixers = { alc260_replacer_672v_mixer }, - .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), - .adc_nids = alc260_adc_nids, - .dig_out_nid = ALC260_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - .unsol_event = alc260_replacer_672v_unsol_event, - .init_hook = alc260_replacer_672v_automute, - }, -#ifdef CONFIG_SND_DEBUG - [ALC260_TEST] = { - .mixers = { alc260_test_mixer }, - .init_verbs = { alc260_test_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), - .dac_nids = alc260_test_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids), - .adc_nids = alc260_test_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources), - .input_mux = alc260_test_capture_sources, - }, -#endif -}; - diff --git a/trunk/sound/pci/hda/alc262_quirks.c b/trunk/sound/pci/hda/alc262_quirks.c deleted file mode 100644 index 8d2097d77642..000000000000 --- a/trunk/sound/pci/hda/alc262_quirks.c +++ /dev/null @@ -1,1353 +0,0 @@ -/* - * ALC262 quirk models - * included by patch_realtek.c - */ - -/* ALC262 models */ -enum { - ALC262_AUTO, - ALC262_BASIC, - ALC262_HIPPO, - ALC262_HIPPO_1, - ALC262_FUJITSU, - ALC262_HP_BPC, - ALC262_HP_BPC_D7000_WL, - ALC262_HP_BPC_D7000_WF, - ALC262_HP_TC_T5735, - ALC262_HP_RP5700, - ALC262_BENQ_ED8, - ALC262_SONY_ASSAMD, - ALC262_BENQ_T31, - ALC262_ULTRA, - ALC262_LENOVO_3000, - ALC262_NEC, - ALC262_TOSHIBA_S06, - ALC262_TOSHIBA_RX1, - ALC262_TYAN, - ALC262_MODEL_LAST /* last tag */ -}; - -#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID -#define ALC262_DIGIN_NID ALC880_DIGIN_NID - -#define alc262_dac_nids alc260_dac_nids -#define alc262_adc_nids alc882_adc_nids -#define alc262_adc_nids_alt alc882_adc_nids_alt -#define alc262_capsrc_nids alc882_capsrc_nids -#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt - -#define alc262_modes alc260_modes -#define alc262_capture_source alc882_capture_source - -static const hda_nid_t alc262_dmic_adc_nids[1] = { - /* ADC0 */ - 0x09 -}; - -static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 }; - -static const struct snd_kcontrol_new alc262_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* update HP, line and mono-out pins according to the master switch */ -#define alc262_hp_master_update alc260_hp_master_update - -static void alc262_hp_bpc_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static void alc262_hp_wildwest_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -#define alc262_hp_master_sw_get alc260_hp_master_sw_get -#define alc262_hp_master_sw_put alc260_hp_master_sw_put - -#define ALC262_HP_MASTER_SWITCH \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Master Playback Switch", \ - .info = snd_ctl_boolean_mono_info, \ - .get = alc262_hp_master_sw_get, \ - .put = alc262_hp_master_sw_put, \ - }, \ - { \ - .iface = NID_MAPPING, \ - .name = "Master Playback Switch", \ - .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \ - } - - -static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { - ALC262_HP_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { - ALC262_HP_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { - HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hp_t5735_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_hp_t5735_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } -}; - -static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_hp_rp5700_verbs[] = { - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, - {} -}; - -static const struct hda_input_mux alc262_hp_rp5700_capture_source = { - .num_items = 1, - .items = { - { "Line", 0x1 }, - }, -}; - -/* bind hp and internal speaker mute (with plug check) as master switch */ -#define alc262_hippo_master_update alc262_hp_master_update -#define alc262_hippo_master_sw_get alc262_hp_master_sw_get -#define alc262_hippo_master_sw_put alc262_hp_master_sw_put - -#define ALC262_HIPPO_MASTER_SWITCH \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Master Playback Switch", \ - .info = snd_ctl_boolean_mono_info, \ - .get = alc262_hippo_master_sw_get, \ - .put = alc262_hippo_master_sw_put, \ - }, \ - { \ - .iface = NID_MAPPING, \ - .name = "Master Playback Switch", \ - .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \ - (SUBDEV_SPEAKER(0) << 16), \ - } - -static const struct snd_kcontrol_new alc262_hippo_mixer[] = { - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_hippo1_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc262_hippo1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - - -static const struct snd_kcontrol_new alc262_sony_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_tyan_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_tyan_verbs[] = { - /* Headphone automute */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* P11 AUX_IN, white 4-pin connector */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1}, - {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93}, - {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19}, - - {} -}; - -/* unsolicited event for HP jack sensing */ -static void alc262_tyan_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - - -#define alc262_capture_mixer alc882_capture_mixer -#define alc262_capture_alt_mixer alc882_capture_alt_mixer - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc262_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - - { } -}; - -static const struct hda_verb alc262_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc262_hippo1_unsol_verbs[] = { - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -static const struct hda_verb alc262_sony_unsol_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic - - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_toshiba_s06_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x09}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static void alc262_toshiba_s06_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -/* - * nec model - * 0x15 = headphone - * 0x16 = internal speaker - * 0x18 = external mic - */ - -static const struct snd_kcontrol_new alc262_nec_mixer[] = { - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_nec_verbs[] = { - /* Unmute Speaker */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Headphone */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* External mic to headphone */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* External mic to speaker */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {} -}; - -/* - * fujitsu model - * 0x14 = headphone/spdif-out, 0x15 = internal speaker, - * 0x1b = port replicator headphone out - */ - -static const struct hda_verb alc262_fujitsu_unsol_verbs[] = { - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = { - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -static const struct hda_verb alc262_lenovo_3000_init_verbs[] = { - /* Front Mic pin: input vref at 50% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {} -}; - -static const struct hda_input_mux alc262_fujitsu_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc262_HP_capture_source = { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "AUX IN", 0x6 }, - }, -}; - -static const struct hda_input_mux alc262_HP_D7000_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x2 }, - { "Line", 0x1 }, - { "CD", 0x4 }, - }, -}; - -static void alc262_fujitsu_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.hp_pins[1] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* bind volumes of both NID 0x0c and 0x0d */ -static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, - .info = snd_ctl_boolean_mono_info, - .get = alc262_hp_master_sw_get, - .put = alc262_hp_master_sw_put, - }, - { - .iface = NID_MAPPING, - .name = "Master Playback Switch", - .private_value = 0x1b, - }, - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static void alc262_lenovo_3000_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, - .info = snd_ctl_boolean_mono_info, - .get = alc262_hp_master_sw_get, - .put = alc262_hp_master_sw_put, - }, - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -/* additional init verbs for Benq laptops */ -static const struct hda_verb alc262_EAPD_verbs[] = { - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, - {} -}; - -static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, - {} -}; - -/* Samsung Q1 Ultra Vista model setup */ -static const struct snd_kcontrol_new alc262_ultra_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc262_ultra_verbs[] = { - /* output mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* speaker */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - /* internal mic */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* ADC, choose mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)}, - {} -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_ultra_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - unsigned int mute; - - mute = 0; - /* auto-mute only when HP is used as HP */ - if (!spec->cur_mux[0]) { - spec->jack_present = snd_hda_jack_detect(codec, 0x15); - if (spec->jack_present) - mute = HDA_AMP_MUTE; - } - /* mute/unmute internal speaker */ - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - /* mute/unmute HP */ - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE); -} - -/* unsolicited event for HP jack sensing */ -static void alc262_ultra_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC_HP_EVENT) - return; - alc262_ultra_automute(codec); -} - -static const struct hda_input_mux alc262_ultra_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Headphone", 0x7 }, - }, -}; - -static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int ret; - - ret = alc_mux_enum_put(kcontrol, ucontrol); - if (!ret) - return 0; - /* reprogram the HP pin as mic or HP according to the input source */ - snd_hda_codec_write_cache(codec, 0x15, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - spec->cur_mux[0] ? PIN_VREF80 : PIN_HP); - alc262_ultra_automute(codec); /* mute/unmute HP */ - return ret; -} - -static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc262_ultra_mux_enum_put, - }, - { - .iface = NID_MAPPING, - .name = "Capture Source", - .private_value = 0x15, - }, - { } /* end */ -}; - -static const struct hda_verb alc262_HP_BPC_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */ - /* Input mixer1: only unmute Mic */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, - - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } -}; - -static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for front - * panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */ - - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/ - /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/ - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, - - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } -}; - -static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) }, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) }, - - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* - * configuration and preset - */ -static const char * const alc262_models[ALC262_MODEL_LAST] = { - [ALC262_BASIC] = "basic", - [ALC262_HIPPO] = "hippo", - [ALC262_HIPPO_1] = "hippo_1", - [ALC262_FUJITSU] = "fujitsu", - [ALC262_HP_BPC] = "hp-bpc", - [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", - [ALC262_HP_TC_T5735] = "hp-tc-t5735", - [ALC262_HP_RP5700] = "hp-rp5700", - [ALC262_BENQ_ED8] = "benq", - [ALC262_BENQ_T31] = "benq-t31", - [ALC262_SONY_ASSAMD] = "sony-assamd", - [ALC262_TOSHIBA_S06] = "toshiba-s06", - [ALC262_TOSHIBA_RX1] = "toshiba-rx1", - [ALC262_ULTRA] = "ultra", - [ALC262_LENOVO_3000] = "lenovo-3000", - [ALC262_NEC] = "nec", - [ALC262_TYAN] = "tyan", - [ALC262_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc262_cfg_tbl[] = { - SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), - SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series", - ALC262_HP_BPC), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series", - ALC262_HP_BPC), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series", - ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", - ALC262_AUTO), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series", - ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735", - ALC262_HP_TC_T5735), - SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700), - SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), - SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), - SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), - SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ - SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), - SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO), - SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO), -#if 0 /* disable the quirk since model=auto works better in recent versions */ - SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", - ALC262_SONY_ASSAMD), -#endif - SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", - ALC262_TOSHIBA_RX1), - SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), - SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), - SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), - SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN), - SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1", - ALC262_ULTRA), - SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO), - SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000), - SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), - SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), - SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), - {} -}; - -static const struct alc_config_preset alc262_presets[] = { - [ALC262_BASIC] = { - .mixers = { alc262_base_mixer }, - .init_verbs = { alc262_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - }, - [ALC262_HIPPO] = { - .mixers = { alc262_hippo_mixer }, - .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs}, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc_inithook, - }, - [ALC262_HIPPO_1] = { - .mixers = { alc262_hippo1_mixer }, - .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs}, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x02, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hippo1_setup, - .init_hook = alc_inithook, - }, - [ALC262_FUJITSU] = { - .mixers = { alc262_fujitsu_mixer }, - .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, - alc262_fujitsu_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_fujitsu_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_fujitsu_setup, - .init_hook = alc_inithook, - }, - [ALC262_HP_BPC] = { - .mixers = { alc262_HP_BPC_mixer }, - .init_verbs = { alc262_HP_BPC_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hp_bpc_setup, - .init_hook = alc_inithook, - }, - [ALC262_HP_BPC_D7000_WF] = { - .mixers = { alc262_HP_BPC_WildWest_mixer }, - .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_HP_D7000_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hp_wildwest_setup, - .init_hook = alc_inithook, - }, - [ALC262_HP_BPC_D7000_WL] = { - .mixers = { alc262_HP_BPC_WildWest_mixer, - alc262_HP_BPC_WildWest_option_mixer }, - .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_HP_D7000_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hp_wildwest_setup, - .init_hook = alc_inithook, - }, - [ALC262_HP_TC_T5735] = { - .mixers = { alc262_hp_t5735_mixer }, - .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hp_t5735_setup, - .init_hook = alc_inithook, - }, - [ALC262_HP_RP5700] = { - .mixers = { alc262_hp_rp5700_mixer }, - .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_hp_rp5700_capture_source, - }, - [ALC262_BENQ_ED8] = { - .mixers = { alc262_base_mixer }, - .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - }, - [ALC262_SONY_ASSAMD] = { - .mixers = { alc262_sony_mixer }, - .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs}, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc_inithook, - }, - [ALC262_BENQ_T31] = { - .mixers = { alc262_benq_t31_mixer }, - .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, - alc_hp15_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc_inithook, - }, - [ALC262_ULTRA] = { - .mixers = { alc262_ultra_mixer }, - .cap_mixer = alc262_ultra_capture_mixer, - .init_verbs = { alc262_ultra_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_ultra_capture_source, - .adc_nids = alc262_adc_nids, /* ADC0 */ - .capsrc_nids = alc262_capsrc_nids, - .num_adc_nids = 1, /* single ADC */ - .unsol_event = alc262_ultra_unsol_event, - .init_hook = alc262_ultra_automute, - }, - [ALC262_LENOVO_3000] = { - .mixers = { alc262_lenovo_3000_mixer }, - .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, - alc262_lenovo_3000_unsol_verbs, - alc262_lenovo_3000_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_fujitsu_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_lenovo_3000_setup, - .init_hook = alc_inithook, - }, - [ALC262_NEC] = { - .mixers = { alc262_nec_mixer }, - .init_verbs = { alc262_nec_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - }, - [ALC262_TOSHIBA_S06] = { - .mixers = { alc262_toshiba_s06_mixer }, - .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs, - alc262_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .capsrc_nids = alc262_dmic_capsrc_nids, - .dac_nids = alc262_dac_nids, - .adc_nids = alc262_dmic_adc_nids, /* ADC0 */ - .num_adc_nids = 1, /* single ADC */ - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_toshiba_s06_setup, - .init_hook = alc_inithook, - }, - [ALC262_TOSHIBA_RX1] = { - .mixers = { alc262_toshiba_rx1_mixer }, - .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc_inithook, - }, - [ALC262_TYAN] = { - .mixers = { alc262_tyan_mixer }, - .init_verbs = { alc262_init_verbs, alc262_tyan_verbs}, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x02, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_tyan_setup, - .init_hook = alc_hp_automute, - }, -}; - diff --git a/trunk/sound/pci/hda/alc268_quirks.c b/trunk/sound/pci/hda/alc268_quirks.c deleted file mode 100644 index be58bf2f3aec..000000000000 --- a/trunk/sound/pci/hda/alc268_quirks.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * ALC267/ALC268 quirk models - * included by patch_realtek.c - */ - -/* ALC268 models */ -enum { - ALC268_AUTO, - ALC267_QUANTA_IL1, - ALC268_3ST, - ALC268_TOSHIBA, - ALC268_ACER, - ALC268_ACER_DMIC, - ALC268_ACER_ASPIRE_ONE, - ALC268_DELL, - ALC268_ZEPTO, -#ifdef CONFIG_SND_DEBUG - ALC268_TEST, -#endif - ALC268_MODEL_LAST /* last tag */ -}; - -/* - * ALC268 channel source setting (2 channel) - */ -#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID -#define alc268_modes alc260_modes - -static const hda_nid_t alc268_dac_nids[2] = { - /* front, hp */ - 0x02, 0x03 -}; - -static const hda_nid_t alc268_adc_nids[2] = { - /* ADC0-1 */ - 0x08, 0x07 -}; - -static const hda_nid_t alc268_adc_nids_alt[1] = { - /* ADC0 */ - 0x08 -}; - -static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 }; - -static const struct snd_kcontrol_new alc268_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc268_toshiba_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc268_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* Toshiba specific */ -static const struct hda_verb alc268_toshiba_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -/* Acer specific */ -/* bind volumes of both NID 0x02 and 0x03 */ -static const struct hda_bind_ctls alc268_acer_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static void alc268_acer_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -#define alc268_acer_master_sw_get alc262_hp_master_sw_get -#define alc268_acer_master_sw_put alc262_hp_master_sw_put - -static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x15, - .info = snd_ctl_boolean_mono_info, - .get = alc268_acer_master_sw_get, - .put = alc268_acer_master_sw_put, - }, - HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc268_acer_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, - .info = snd_ctl_boolean_mono_info, - .get = alc268_acer_master_sw_get, - .put = alc268_acer_master_sw_put, - }, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, - .info = snd_ctl_boolean_mono_info, - .get = alc268_acer_master_sw_get, - .put = alc268_acer_master_sw_put, - }, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc268_acer_aspire_one_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x23, AC_VERB_SET_CONNECT_SEL, 0x06}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017}, - { } -}; - -static const struct hda_verb alc268_acer_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } -}; - -/* unsolicited event for HP jack sensing */ -#define alc268_toshiba_setup alc262_hippo_setup - -static void alc268_acer_lc_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -static const struct snd_kcontrol_new alc268_dell_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc268_dell_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - { } -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc268_dell_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc267_quanta_il1_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - { } -}; - -static void alc267_quanta_il1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc268_base_init_verbs[] = { - /* Unmute DAC0-1 and set vol = 0 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* set PCBEEP vol = 0, mute connections */ - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Unmute Selector 23h,24h and set the default input to mic-in */ - - {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - { } -}; - -/* only for model=test */ -#ifdef CONFIG_SND_DEBUG -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc268_volume_init_verbs[] = { - /* set output DAC */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - { } -}; -#endif /* CONFIG_SND_DEBUG */ - -static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), - _DEFINE_CAPSRC(1), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc268_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT), - _DEFINE_CAPSRC(2), - { } /* end */ -}; - -static const struct hda_input_mux alc268_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x3 }, - }, -}; - -static const struct hda_input_mux alc268_acer_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux alc268_acer_dmic_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x6 }, - { "Line", 0x2 }, - }, -}; - -#ifdef CONFIG_SND_DEBUG -static const struct snd_kcontrol_new alc268_test_mixer[] = { - /* Volume widgets */ - HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT), - HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT), - HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT), - HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT), - HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT), - /* The below appears problematic on some hardwares */ - /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/ - HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT), - - /* Controls for GPIO pins, assuming they are configured as outputs */ - ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), - ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), - ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), - ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), - - /* Switches to allow the digital SPDIF output pin to be enabled. - * The ALC268 does not have an SPDIF input. - */ - ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01), - - /* A switch allowing EAPD to be enabled. Some laptops seem to use - * this output to turn on an external amplifier. - */ - ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), - ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), - - { } /* end */ -}; -#endif - -/* - * configuration and preset - */ -static const char * const alc268_models[ALC268_MODEL_LAST] = { - [ALC267_QUANTA_IL1] = "quanta-il1", - [ALC268_3ST] = "3stack", - [ALC268_TOSHIBA] = "toshiba", - [ALC268_ACER] = "acer", - [ALC268_ACER_DMIC] = "acer-dmic", - [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", - [ALC268_DELL] = "dell", - [ALC268_ZEPTO] = "zepto", -#ifdef CONFIG_SND_DEBUG - [ALC268_TEST] = "test", -#endif - [ALC268_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc268_cfg_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", - ALC268_ACER_ASPIRE_ONE), - SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), - SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO), - SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0, - "Dell Inspiron Mini9/Vostro A90", ALC268_DELL), - /* almost compatible with toshiba but with optional digital outs; - * auto-probing seems working fine - */ - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series", - ALC268_AUTO), - SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), - SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), - SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), - SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), - {} -}; - -/* Toshiba laptops have no unique PCI SSID but only codec SSID */ -static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { - SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO), - SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO), - SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", - ALC268_TOSHIBA), - {} -}; - -static const struct alc_config_preset alc268_presets[] = { - [ALC267_QUANTA_IL1] = { - .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer, - alc268_capture_nosrc_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc267_quanta_il1_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc267_quanta_il1_setup, - .init_hook = alc_inithook, - }, - [ALC268_3ST] = { - .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC268_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - }, - [ALC268_TOSHIBA] = { - .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_toshiba_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_toshiba_setup, - .init_hook = alc_inithook, - }, - [ALC268_ACER] = { - .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_acer_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_acer_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_acer_setup, - .init_hook = alc_inithook, - }, - [ALC268_ACER_DMIC] = { - .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_acer_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_acer_dmic_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_acer_setup, - .init_hook = alc_inithook, - }, - [ALC268_ACER_ASPIRE_ONE] = { - .mixers = { alc268_acer_aspire_one_mixer, - alc268_beep_mixer, - alc268_capture_nosrc_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_acer_aspire_one_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_acer_lc_setup, - .init_hook = alc_inithook, - }, - [ALC268_DELL] = { - .mixers = { alc268_dell_mixer, alc268_beep_mixer, - alc268_capture_nosrc_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_dell_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_dell_setup, - .init_hook = alc_inithook, - }, - [ALC268_ZEPTO] = { - .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_toshiba_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC268_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_toshiba_setup, - .init_hook = alc_inithook, - }, -#ifdef CONFIG_SND_DEBUG - [ALC268_TEST] = { - .mixers = { alc268_test_mixer, alc268_capture_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_volume_init_verbs, - alc268_beep_init_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC268_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - }, -#endif -}; - diff --git a/trunk/sound/pci/hda/alc269_quirks.c b/trunk/sound/pci/hda/alc269_quirks.c deleted file mode 100644 index 14fdcf29b154..000000000000 --- a/trunk/sound/pci/hda/alc269_quirks.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - * ALC269/ALC270/ALC275/ALC276 quirk models - * included by patch_realtek.c - */ - -/* ALC269 models */ -enum { - ALC269_AUTO, - ALC269_BASIC, - ALC269_QUANTA_FL1, - ALC269_AMIC, - ALC269_DMIC, - ALC269VB_AMIC, - ALC269VB_DMIC, - ALC269_FUJITSU, - ALC269_LIFEBOOK, - ALC271_ACER, - ALC269_MODEL_LAST /* last tag */ -}; - -/* - * ALC269 channel source setting (2 channel) - */ -#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID - -#define alc269_dac_nids alc260_dac_nids - -static const hda_nid_t alc269_adc_nids[1] = { - /* ADC1 */ - 0x08, -}; - -static const hda_nid_t alc269_capsrc_nids[1] = { - 0x23, -}; - -static const hda_nid_t alc269vb_adc_nids[1] = { - /* ADC1 */ - 0x09, -}; - -static const hda_nid_t alc269vb_capsrc_nids[1] = { - 0x22, -}; - -#define alc269_modes alc260_modes -#define alc269_capture_source alc880_lg_lw_capture_source - -static const struct snd_kcontrol_new alc269_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc269_lifebook_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc269_laptop_mixer[] = { - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = { - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269_asus_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* capture mixer elements */ -static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -/* FSC amilo */ -#define alc269_fujitsu_mixer alc269_laptop_mixer - -static const struct hda_verb alc269_quanta_fl1_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - { } -}; - -static const struct hda_verb alc269_lifebook_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) -{ - alc_hp_automute(codec); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x680); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x480); -} - -#define alc269_lifebook_speaker_automute \ - alc269_quanta_fl1_speaker_automute - -static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) -{ - unsigned int present_laptop; - unsigned int present_dock; - - present_laptop = snd_hda_jack_detect(codec, 0x18); - present_dock = snd_hda_jack_detect(codec, 0x1b); - - /* Laptop mic port overrides dock mic port, design decision */ - if (present_dock) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x3); - if (present_laptop) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x0); - if (!present_dock && !present_laptop) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x1); -} - -static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC_HP_EVENT: - alc269_quanta_fl1_speaker_automute(codec); - break; - case ALC_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -static void alc269_lifebook_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc269_lifebook_speaker_automute(codec); - if ((res >> 26) == ALC_MIC_EVENT) - alc269_lifebook_mic_autoswitch(codec); -} - -static void alc269_quanta_fl1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) -{ - alc269_quanta_fl1_speaker_automute(codec); - alc_mic_automute(codec); -} - -static void alc269_lifebook_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.hp_pins[1] = 0x1a; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; -} - -static void alc269_lifebook_init_hook(struct hda_codec *codec) -{ - alc269_lifebook_speaker_automute(codec); - alc269_lifebook_mic_autoswitch(codec); -} - -static const struct hda_verb alc269_laptop_dmic_init_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc269_laptop_amic_init_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x06}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = { - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc271_acer_dmic_verbs[] = { - {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, - {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x22, AC_VERB_SET_CONNECT_SEL, 6}, - { } -}; - -static void alc269_laptop_amic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc269_laptop_dmic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -static void alc269vb_laptop_amic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc269_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* - * Set up output mixers (0x02 - 0x03) - */ - /* set vol=0 to output mixers */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* FIXME: use Mux-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* set EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc269vb_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* - * Set up output mixers (0x02 - 0x03) - */ - /* set vol=0 to output mixers */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* FIXME: use Mux-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x22, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* set EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* - * configuration and preset - */ -static const char * const alc269_models[ALC269_MODEL_LAST] = { - [ALC269_BASIC] = "basic", - [ALC269_QUANTA_FL1] = "quanta", - [ALC269_AMIC] = "laptop-amic", - [ALC269_DMIC] = "laptop-dmic", - [ALC269_FUJITSU] = "fujitsu", - [ALC269_LIFEBOOK] = "lifebook", - [ALC269_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc269_cfg_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), - SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER), - SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", - ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", - ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", - ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC), - SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO), - SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), - SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC), - SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), - SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC), - SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC), - SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC), - {} -}; - -static const struct alc_config_preset alc269_presets[] = { - [ALC269_BASIC] = { - .mixers = { alc269_base_mixer }, - .init_verbs = { alc269_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - }, - [ALC269_QUANTA_FL1] = { - .mixers = { alc269_quanta_fl1_mixer }, - .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - .unsol_event = alc269_quanta_fl1_unsol_event, - .setup = alc269_quanta_fl1_setup, - .init_hook = alc269_quanta_fl1_init_hook, - }, - [ALC269_AMIC] = { - .mixers = { alc269_laptop_mixer }, - .cap_mixer = alc269_laptop_analog_capture_mixer, - .init_verbs = { alc269_init_verbs, - alc269_laptop_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269_laptop_amic_setup, - .init_hook = alc_inithook, - }, - [ALC269_DMIC] = { - .mixers = { alc269_laptop_mixer }, - .cap_mixer = alc269_laptop_digital_capture_mixer, - .init_verbs = { alc269_init_verbs, - alc269_laptop_dmic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269_laptop_dmic_setup, - .init_hook = alc_inithook, - }, - [ALC269VB_AMIC] = { - .mixers = { alc269vb_laptop_mixer }, - .cap_mixer = alc269vb_laptop_analog_capture_mixer, - .init_verbs = { alc269vb_init_verbs, - alc269vb_laptop_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269vb_laptop_amic_setup, - .init_hook = alc_inithook, - }, - [ALC269VB_DMIC] = { - .mixers = { alc269vb_laptop_mixer }, - .cap_mixer = alc269vb_laptop_digital_capture_mixer, - .init_verbs = { alc269vb_init_verbs, - alc269vb_laptop_dmic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269vb_laptop_dmic_setup, - .init_hook = alc_inithook, - }, - [ALC269_FUJITSU] = { - .mixers = { alc269_fujitsu_mixer }, - .cap_mixer = alc269_laptop_digital_capture_mixer, - .init_verbs = { alc269_init_verbs, - alc269_laptop_dmic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269_laptop_dmic_setup, - .init_hook = alc_inithook, - }, - [ALC269_LIFEBOOK] = { - .mixers = { alc269_lifebook_mixer }, - .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - .unsol_event = alc269_lifebook_unsol_event, - .setup = alc269_lifebook_setup, - .init_hook = alc269_lifebook_init_hook, - }, - [ALC271_ACER] = { - .mixers = { alc269_asus_mixer }, - .cap_mixer = alc269vb_laptop_digital_capture_mixer, - .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .adc_nids = alc262_dmic_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids), - .capsrc_nids = alc262_dmic_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - .dig_out_nid = ALC880_DIGOUT_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc269vb_laptop_dmic_setup, - .init_hook = alc_inithook, - }, -}; - diff --git a/trunk/sound/pci/hda/alc662_quirks.c b/trunk/sound/pci/hda/alc662_quirks.c deleted file mode 100644 index e69a6ea3083a..000000000000 --- a/trunk/sound/pci/hda/alc662_quirks.c +++ /dev/null @@ -1,1408 +0,0 @@ -/* - * ALC662/ALC663/ALC665/ALC670 quirk models - * included by patch_realtek.c - */ - -/* ALC662 models */ -enum { - ALC662_AUTO, - ALC662_3ST_2ch_DIG, - ALC662_3ST_6ch_DIG, - ALC662_3ST_6ch, - ALC662_5ST_DIG, - ALC662_LENOVO_101E, - ALC662_ASUS_EEEPC_P701, - ALC662_ASUS_EEEPC_EP20, - ALC663_ASUS_M51VA, - ALC663_ASUS_G71V, - ALC663_ASUS_H13, - ALC663_ASUS_G50V, - ALC662_ECS, - ALC663_ASUS_MODE1, - ALC662_ASUS_MODE2, - ALC663_ASUS_MODE3, - ALC663_ASUS_MODE4, - ALC663_ASUS_MODE5, - ALC663_ASUS_MODE6, - ALC663_ASUS_MODE7, - ALC663_ASUS_MODE8, - ALC272_DELL, - ALC272_DELL_ZM1, - ALC272_SAMSUNG_NC10, - ALC662_MODEL_LAST, -}; - -#define ALC662_DIGOUT_NID 0x06 -#define ALC662_DIGIN_NID 0x0a - -static const hda_nid_t alc662_dac_nids[3] = { - /* front, rear, clfe */ - 0x02, 0x03, 0x04 -}; - -static const hda_nid_t alc272_dac_nids[2] = { - 0x02, 0x03 -}; - -static const hda_nid_t alc662_adc_nids[2] = { - /* ADC1-2 */ - 0x09, 0x08 -}; - -static const hda_nid_t alc272_adc_nids[1] = { - /* ADC1-2 */ - 0x08, -}; - -static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; -static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; - - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ -static const struct hda_input_mux alc662_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc662_lenovo_101e_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux alc663_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -#if 0 /* set to 1 for testing other input sources below */ -static const struct hda_input_mux alc272_nc10_capture_source = { - .num_items = 16, - .items = { - { "Autoselect Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "In-0x02", 0x2 }, - { "In-0x03", 0x3 }, - { "In-0x04", 0x4 }, - { "In-0x05", 0x5 }, - { "In-0x06", 0x6 }, - { "In-0x07", 0x7 }, - { "In-0x08", 0x8 }, - { "In-0x09", 0x9 }, - { "In-0x0a", 0x0a }, - { "In-0x0b", 0x0b }, - { "In-0x0c", 0x0c }, - { "In-0x0d", 0x0d }, - { "In-0x0e", 0x0e }, - { "In-0x0f", 0x0f }, - }, -}; -#endif - -/* - * 2ch mode - */ -static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc662_3ST_ch2_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc662_3ST_ch6_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = { - { 2, alc662_3ST_ch2_init }, - { 6, alc662_3ST_ch6_init }, -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc662_sixstack_ch6_init[] = { - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc662_sixstack_ch8_init[] = { - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static const struct hda_channel_mode alc662_5stack_modes[2] = { - { 2, alc662_sixstack_ch6_init }, - { 6, alc662_sixstack_ch8_init }, -}; - -/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 - * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b - */ - -static const struct snd_kcontrol_new alc662_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - /*Input mixer control */ - HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc663_asus_one_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_m51va_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_tree_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_four_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_1bjd_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc663_asus_two_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", - &alc663_asus_two_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_g71v_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_g50v_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_mode7_mixer[] = { - HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), - HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), - HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_mode8_mixer[] = { - HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), - HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), - HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - - -static const struct snd_kcontrol_new alc662_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc662_init_verbs[] = { - /* ADC: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Rear Pin: output 1 (0x0d) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - { } -}; - -static const struct hda_verb alc662_eapd_init_verbs[] = { - /* always trun on EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc662_sue_init_verbs[] = { - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_FRONT_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc662_eeepc_sue_init_verbs[] = { - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* Set Unsolicited Event*/ -static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_m51va_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_21jd_amic_init_verbs[] = { - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc662_1bjd_amic_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_15jd_amic_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_g71v_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ - /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ - - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_FRONT_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_g50v_init_verbs[] = { - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc662_ecs_init_verbs[] = { - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc272_dell_zm1_init_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc272_dell_init_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_mode7_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_mode8_init_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { } /* end */ -}; - -static void alc662_lenovo_101e_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.line_out_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->detect_line = 1; - spec->automute_lines = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc662_eeepc_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - alc262_hippo1_setup(codec); - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc662_eeepc_ep20_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc663_m51va_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -/* ***************** Mode1 ******************************/ -static void alc663_mode1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode2 ******************************/ -static void alc662_mode2_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode3 ******************************/ -static void alc663_mode3_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode4 ******************************/ -static void alc663_mode4_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute_mixer_nid[1] = 0x0e; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode5 ******************************/ -static void alc663_mode5_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute_mixer_nid[1] = 0x0e; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode6 ******************************/ -static void alc663_mode6_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode7 ******************************/ -static void alc663_mode7_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode8 ******************************/ -static void alc663_mode8_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.hp_pins[1] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -static void alc663_g71v_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.line_out_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; - spec->detect_line = 1; - spec->automute_lines = 1; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -#define alc663_g50v_setup alc663_m51va_setup - -static const struct snd_kcontrol_new alc662_ecs_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - - HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc272_nc10_mixer[] = { - /* Master Playback automatically created from Speaker and Headphone */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - - -/* - * configuration and preset - */ -static const char * const alc662_models[ALC662_MODEL_LAST] = { - [ALC662_3ST_2ch_DIG] = "3stack-dig", - [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", - [ALC662_3ST_6ch] = "3stack-6ch", - [ALC662_5ST_DIG] = "5stack-dig", - [ALC662_LENOVO_101E] = "lenovo-101e", - [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", - [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", - [ALC662_ECS] = "ecs", - [ALC663_ASUS_M51VA] = "m51va", - [ALC663_ASUS_G71V] = "g71v", - [ALC663_ASUS_H13] = "h13", - [ALC663_ASUS_G50V] = "g50v", - [ALC663_ASUS_MODE1] = "asus-mode1", - [ALC662_ASUS_MODE2] = "asus-mode2", - [ALC663_ASUS_MODE3] = "asus-mode3", - [ALC663_ASUS_MODE4] = "asus-mode4", - [ALC663_ASUS_MODE5] = "asus-mode5", - [ALC663_ASUS_MODE6] = "asus-mode6", - [ALC663_ASUS_MODE7] = "asus-mode7", - [ALC663_ASUS_MODE8] = "asus-mode8", - [ALC272_DELL] = "dell", - [ALC272_DELL_ZM1] = "dell-zm1", - [ALC272_SAMSUNG_NC10] = "samsung-nc10", - [ALC662_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc662_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), - SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL), - SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), - SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7), - SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7), - SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8), - SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5), - SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), - /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/ - SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V), - /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/ - SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4), - SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), - SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), - SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), - SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", - ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO), - SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", - ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13), - SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), - SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0", - ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x", - ALC663_ASUS_H13), - SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E), - {} -}; - -static const struct alc_config_preset alc662_presets[] = { - [ALC662_3ST_2ch_DIG] = { - .mixers = { alc662_3ST_2ch_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_capture_source, - }, - [ALC662_3ST_6ch_DIG] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc662_capture_source, - }, - [ALC662_3ST_6ch] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc662_capture_source, - }, - [ALC662_5ST_DIG] = { - .mixers = { alc662_base_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes), - .channel_mode = alc662_5stack_modes, - .input_mux = &alc662_capture_source, - }, - [ALC662_LENOVO_101E] = { - .mixers = { alc662_lenovo_101e_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_sue_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_lenovo_101e_setup, - .init_hook = alc_inithook, - }, - [ALC662_ASUS_EEEPC_P701] = { - .mixers = { alc662_eeepc_p701_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_eeepc_sue_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_eeepc_setup, - .init_hook = alc_inithook, - }, - [ALC662_ASUS_EEEPC_EP20] = { - .mixers = { alc662_eeepc_ep20_mixer, - alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_eeepc_ep20_sue_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_eeepc_ep20_setup, - .init_hook = alc_inithook, - }, - [ALC662_ECS] = { - .mixers = { alc662_ecs_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_ecs_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_eeepc_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_M51VA] = { - .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_m51va_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_m51va_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_G71V] = { - .mixers = { alc663_g71v_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_g71v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_g71v_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_H13] = { - .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_m51va_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .setup = alc663_m51va_setup, - .unsol_event = alc_sku_unsol_event, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_G50V] = { - .mixers = { alc663_g50v_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_g50v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .input_mux = &alc663_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_g50v_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE1] = { - .mixers = { alc663_m51va_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_21jd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode1_setup, - .init_hook = alc_inithook, - }, - [ALC662_ASUS_MODE2] = { - .mixers = { alc662_1bjd_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_1bjd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_mode2_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE3] = { - .mixers = { alc663_two_hp_m1_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_two_hp_amic_m1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode3_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE4] = { - .mixers = { alc663_asus_21jd_clfe_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_21jd_amic_init_verbs}, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode4_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE5] = { - .mixers = { alc663_asus_15jd_clfe_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_15jd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode5_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE6] = { - .mixers = { alc663_two_hp_m2_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_two_hp_amic_m2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode6_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE7] = { - .mixers = { alc663_mode7_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_mode7_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode7_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE8] = { - .mixers = { alc663_mode8_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_mode8_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode8_setup, - .init_hook = alc_inithook, - }, - [ALC272_DELL] = { - .mixers = { alc663_m51va_mixer }, - .cap_mixer = alc272_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc272_dell_init_verbs }, - .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc272_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .adc_nids = alc272_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), - .capsrc_nids = alc272_capsrc_nids, - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_m51va_setup, - .init_hook = alc_inithook, - }, - [ALC272_DELL_ZM1] = { - .mixers = { alc663_m51va_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc272_dell_zm1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc272_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .adc_nids = alc662_adc_nids, - .num_adc_nids = 1, - .capsrc_nids = alc662_capsrc_nids, - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_m51va_setup, - .init_hook = alc_inithook, - }, - [ALC272_SAMSUNG_NC10] = { - .mixers = { alc272_nc10_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_21jd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc272_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - /*.input_mux = &alc272_nc10_capture_source,*/ - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode4_setup, - .init_hook = alc_inithook, - }, -}; - - diff --git a/trunk/sound/pci/hda/alc680_quirks.c b/trunk/sound/pci/hda/alc680_quirks.c deleted file mode 100644 index 0eeb227c7bc2..000000000000 --- a/trunk/sound/pci/hda/alc680_quirks.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * ALC680 quirk models - * included by patch_realtek.c - */ - -/* ALC680 models */ -enum { - ALC680_AUTO, - ALC680_BASE, - ALC680_MODEL_LAST, -}; - -#define ALC680_DIGIN_NID ALC880_DIGIN_NID -#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID -#define alc680_modes alc260_modes - -static const hda_nid_t alc680_dac_nids[3] = { - /* Lout1, Lout2, hp */ - 0x02, 0x03, 0x04 -}; - -static const hda_nid_t alc680_adc_nids[3] = { - /* ADC0-2 */ - /* DMIC, MIC, Line-in*/ - 0x07, 0x08, 0x09 -}; - -/* - * Analog capture ADC cgange - */ -static hda_nid_t alc680_get_cur_adc(struct hda_codec *codec) -{ - static hda_nid_t pins[] = {0x18, 0x19}; - static hda_nid_t adcs[] = {0x08, 0x09}; - int i; - - for (i = 0; i < ARRAY_SIZE(pins); i++) { - if (!is_jack_detectable(codec, pins[i])) - continue; - if (snd_hda_jack_detect(codec, pins[i])) - return adcs[i]; - } - return 0x07; -} - -static void alc680_rec_autoswitch(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid = alc680_get_cur_adc(codec); - if (spec->cur_adc && nid != spec->cur_adc) { - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = nid; - snd_hda_codec_setup_stream(codec, nid, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } -} - -static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid = alc680_get_cur_adc(codec); - - spec->cur_adc = nid; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); - return 0; -} - -static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; -} - -static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = { - .substreams = 1, /* can be overridden */ - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .prepare = alc680_capture_pcm_prepare, - .cleanup = alc680_capture_pcm_cleanup - }, -}; - -static const struct snd_kcontrol_new alc680_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct hda_bind_ctls alc680_bind_cap_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc680_bind_cap_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc680_master_capture_mixer[] = { - HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), - HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), - { } /* end */ -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc680_init_verbs[] = { - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc680_base_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x16; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.num_inputs = 2; - spec->autocfg.inputs[0].pin = 0x18; - spec->autocfg.inputs[0].type = AUTO_PIN_MIC; - spec->autocfg.inputs[1].pin = 0x19; - spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc680_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc_hp_automute(codec); - if ((res >> 26) == ALC_MIC_EVENT) - alc680_rec_autoswitch(codec); -} - -static void alc680_inithook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc680_rec_autoswitch(codec); -} - -/* - * configuration and preset - */ -static const char * const alc680_models[ALC680_MODEL_LAST] = { - [ALC680_BASE] = "base", - [ALC680_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc680_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), - {} -}; - -static const struct alc_config_preset alc680_presets[] = { - [ALC680_BASE] = { - .mixers = { alc680_base_mixer }, - .cap_mixer = alc680_master_capture_mixer, - .init_verbs = { alc680_init_verbs }, - .num_dacs = ARRAY_SIZE(alc680_dac_nids), - .dac_nids = alc680_dac_nids, - .dig_out_nid = ALC680_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc680_modes), - .channel_mode = alc680_modes, - .unsol_event = alc680_unsol_event, - .setup = alc680_base_setup, - .init_hook = alc680_inithook, - - }, -}; diff --git a/trunk/sound/pci/hda/alc861_quirks.c b/trunk/sound/pci/hda/alc861_quirks.c deleted file mode 100644 index d719ec6350eb..000000000000 --- a/trunk/sound/pci/hda/alc861_quirks.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - * ALC660/ALC861 quirk models - * included by patch_realtek.c - */ - -/* ALC861 models */ -enum { - ALC861_AUTO, - ALC861_3ST, - ALC660_3ST, - ALC861_3ST_DIG, - ALC861_6ST_DIG, - ALC861_UNIWILL_M31, - ALC861_TOSHIBA, - ALC861_ASUS, - ALC861_ASUS_LAPTOP, - ALC861_MODEL_LAST, -}; - -/* - * ALC861 channel source setting (2/6 channel selection for 3-stack) - */ - -/* - * set the path ways for 2 channel output - * need to set the codec line out and mic 1 pin widgets to inputs - */ -static const struct hda_verb alc861_threestack_ch2_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* set pin widget 18h (mic1/2) for input, for mic also enable - * the vref - */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ -#endif - { } /* end */ -}; -/* - * 6ch mode - * need to set the codec line out and mic 1 pin widgets to outputs - */ -static const struct hda_verb alc861_threestack_ch6_init[] = { - /* set pin widget 1Ah (line in) for output (Back Surround)*/ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* set pin widget 18h (mic1) for output (CLFE)*/ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - - { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ -#endif - { } /* end */ -}; - -static const struct hda_channel_mode alc861_threestack_modes[2] = { - { 2, alc861_threestack_ch2_init }, - { 6, alc861_threestack_ch6_init }, -}; -/* Set mic1 as input and unmute the mixer */ -static const struct hda_verb alc861_uniwill_m31_ch2_init[] = { - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { } /* end */ -}; -/* Set mic1 as output and mute mixer */ -static const struct hda_verb alc861_uniwill_m31_ch4_init[] = { - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { } /* end */ -}; - -static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = { - { 2, alc861_uniwill_m31_ch2_init }, - { 4, alc861_uniwill_m31_ch4_init }, -}; - -/* Set mic1 and line-in as input and unmute the mixer */ -static const struct hda_verb alc861_asus_ch2_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* set pin widget 18h (mic1/2) for input, for mic also enable - * the vref - */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ -#endif - { } /* end */ -}; -/* Set mic1 nad line-in as output and mute mixer */ -static const struct hda_verb alc861_asus_ch6_init[] = { - /* set pin widget 1Ah (line in) for output (Back Surround)*/ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ - /* set pin widget 18h (mic1) for output (CLFE)*/ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ - { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ -#endif - { } /* end */ -}; - -static const struct hda_channel_mode alc861_asus_modes[2] = { - { 2, alc861_asus_ch2_init }, - { 6, alc861_asus_ch6_init }, -}; - -/* patch-ALC861 */ - -static const struct snd_kcontrol_new alc861_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), - - /*Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_3ST_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ - - /* Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_threestack_modes), - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_toshiba_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ - - /* Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes), - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_asus_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), - - /* Input mixer control */ - HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_asus_modes), - }, - { } -}; - -/* additional mixer */ -static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - { } -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc861_base_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - - { } -}; - -static const struct hda_verb alc861_threestack_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -static const struct hda_verb alc861_uniwill_m31_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - /* this has to be set to VREF80 */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -static const struct hda_verb alc861_asus_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) - * according to codec#0 this is the HP jack - */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */ - /* route front PCM to HP */ - { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - /* this has to be set to VREF80 */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -/* additional init verbs for ASUS laptops */ -static const struct hda_verb alc861_asus_laptop_init_verbs[] = { - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */ - { } -}; - -static const struct hda_verb alc861_toshiba_init_verbs[] = { - {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc861_toshiba_automute(struct hda_codec *codec) -{ - unsigned int present = snd_hda_jack_detect(codec, 0x0f); - - snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, - HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); -} - -static void alc861_toshiba_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc861_toshiba_automute(codec); -} - -#define ALC861_DIGOUT_NID 0x07 - -static const struct hda_channel_mode alc861_8ch_modes[1] = { - { 8, NULL } -}; - -static const hda_nid_t alc861_dac_nids[4] = { - /* front, surround, clfe, side */ - 0x03, 0x06, 0x05, 0x04 -}; - -static const hda_nid_t alc660_dac_nids[3] = { - /* front, clfe, surround */ - 0x03, 0x05, 0x06 -}; - -static const hda_nid_t alc861_adc_nids[1] = { - /* ADC0-2 */ - 0x08, -}; - -static const struct hda_input_mux alc861_capture_source = { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x1 }, - { "CD", 0x4 }, - { "Mixer", 0x5 }, - }, -}; - -/* - * configuration and preset - */ -static const char * const alc861_models[ALC861_MODEL_LAST] = { - [ALC861_3ST] = "3stack", - [ALC660_3ST] = "3stack-660", - [ALC861_3ST_DIG] = "3stack-dig", - [ALC861_6ST_DIG] = "6stack-dig", - [ALC861_UNIWILL_M31] = "uniwill-m31", - [ALC861_TOSHIBA] = "toshiba", - [ALC861_ASUS] = "asus", - [ALC861_ASUS_LAPTOP] = "asus-laptop", - [ALC861_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc861_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), - SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), - SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG), - SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), - /* FIXME: the entry below breaks Toshiba A100 (model=auto works!) - * Any other models that need this preset? - */ - /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */ - SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST), - SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST), - SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), - SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), - SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP), - /* FIXME: the below seems conflict */ - /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */ - SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), - SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), - {} -}; - -static const struct alc_config_preset alc861_presets[] = { - [ALC861_3ST] = { - .mixers = { alc861_3ST_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_3ST_DIG] = { - .mixers = { alc861_base_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_6ST_DIG] = { - .mixers = { alc861_base_mixer }, - .init_verbs = { alc861_base_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes), - .channel_mode = alc861_8ch_modes, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC660_3ST] = { - .mixers = { alc861_3ST_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660_dac_nids), - .dac_nids = alc660_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_UNIWILL_M31] = { - .mixers = { alc861_uniwill_m31_mixer }, - .init_verbs = { alc861_uniwill_m31_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes), - .channel_mode = alc861_uniwill_m31_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_TOSHIBA] = { - .mixers = { alc861_toshiba_mixer }, - .init_verbs = { alc861_base_init_verbs, - alc861_toshiba_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - .unsol_event = alc861_toshiba_unsol_event, - .init_hook = alc861_toshiba_automute, - }, - [ALC861_ASUS] = { - .mixers = { alc861_asus_mixer }, - .init_verbs = { alc861_asus_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_asus_modes), - .channel_mode = alc861_asus_modes, - .need_dac_fix = 1, - .hp_nid = 0x06, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_ASUS_LAPTOP] = { - .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer }, - .init_verbs = { alc861_asus_init_verbs, - alc861_asus_laptop_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, -}; - diff --git a/trunk/sound/pci/hda/alc861vd_quirks.c b/trunk/sound/pci/hda/alc861vd_quirks.c deleted file mode 100644 index 8f28450f41f8..000000000000 --- a/trunk/sound/pci/hda/alc861vd_quirks.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * ALC660-VD/ALC861-VD quirk models - * included by patch_realtek.c - */ - -/* ALC861-VD models */ -enum { - ALC861VD_AUTO, - ALC660VD_3ST, - ALC660VD_3ST_DIG, - ALC660VD_ASUS_V1S, - ALC861VD_3ST, - ALC861VD_3ST_DIG, - ALC861VD_6ST_DIG, - ALC861VD_LENOVO, - ALC861VD_DALLAS, - ALC861VD_HP, - ALC861VD_MODEL_LAST, -}; - -#define ALC861VD_DIGOUT_NID 0x06 - -static const hda_nid_t alc861vd_dac_nids[4] = { - /* front, surr, clfe, side surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -/* dac_nids for ALC660vd are in a different order - according to - * Realtek's driver. - * This should probably result in a different mixer for 6stack models - * of ALC660vd codecs, but for now there is only 3stack mixer - * - and it is the same as in 861vd. - * adc_nids in ALC660vd are (is) the same as in 861vd - */ -static const hda_nid_t alc660vd_dac_nids[3] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x04, 0x03 -}; - -static const hda_nid_t alc861vd_adc_nids[1] = { - /* ADC0 */ - 0x09, -}; - -static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 }; - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ -static const struct hda_input_mux alc861vd_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc861vd_dallas_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - }, -}; - -static const struct hda_input_mux alc861vd_hp_capture_source = { - .num_items = 2, - .items = { - { "Front Mic", 0x0 }, - { "ATAPI Mic", 0x1 }, - }, -}; - -/* - * 2ch mode - */ -static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc861vd_6stack_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc861vd_6stack_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static const struct hda_channel_mode alc861vd_6stack_modes[2] = { - { 6, alc861vd_6stack_ch6_init }, - { 8, alc861vd_6stack_ch8_init }, -}; - -static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 - * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b - */ -static const struct snd_kcontrol_new alc861vd_6st_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861vd_3st_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/ - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - { } /* end */ -}; - -/* Pin assignment: Speaker=0x14, HP = 0x15, - * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d - */ -static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -/* Pin assignment: Speaker=0x14, Line-out = 0x15, - * Front Mic=0x18, ATAPI Mic = 0x19, - */ -static const struct snd_kcontrol_new alc861vd_hp_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - { } /* end */ -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc861vd_volume_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of - * the analog-loopback mixer widget - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x02 - 0x05) - */ - /* set vol=0 to output mixers */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - { } -}; - -/* - * 3-stack pin configuration: - * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b - */ -static const struct hda_verb alc861vd_3stack_init_verbs[] = { - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 6-stack pin configuration: - */ -static const struct hda_verb alc861vd_6stack_init_verbs[] = { - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Rear Pin: output 1 (0x0d) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -static const struct hda_verb alc861vd_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {} -}; - -static void alc861vd_lenovo_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc861vd_lenovo_init_hook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc88x_simple_mic_automute(codec); -} - -static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC_MIC_EVENT: - alc88x_simple_mic_automute(codec); - break; - default: - alc_sku_unsol_event(codec, res); - break; - } -} - -static const struct hda_verb alc861vd_dallas_verbs[] = { - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - - { } /* end */ -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc861vd_dallas_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* - * configuration and preset - */ -static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = { - [ALC660VD_3ST] = "3stack-660", - [ALC660VD_3ST_DIG] = "3stack-660-digout", - [ALC660VD_ASUS_V1S] = "asus-v1s", - [ALC861VD_3ST] = "3stack", - [ALC861VD_3ST_DIG] = "3stack-digout", - [ALC861VD_6ST_DIG] = "6stack-digout", - [ALC861VD_LENOVO] = "lenovo", - [ALC861VD_DALLAS] = "dallas", - [ALC861VD_HP] = "hp", - [ALC861VD_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc861vd_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), - SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), - SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), - /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */ - SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S), - SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), - SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), - SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), - /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ - SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS), - SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), - SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), - {} -}; - -static const struct alc_config_preset alc861vd_presets[] = { - [ALC660VD_3ST] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC660VD_3ST_DIG] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_3ST] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_3ST_DIG] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_6ST_DIG] = { - .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes), - .channel_mode = alc861vd_6stack_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_LENOVO] = { - .mixers = { alc861vd_lenovo_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs, - alc861vd_eapd_verbs, - alc861vd_lenovo_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - .unsol_event = alc861vd_lenovo_unsol_event, - .setup = alc861vd_lenovo_setup, - .init_hook = alc861vd_lenovo_init_hook, - }, - [ALC861VD_DALLAS] = { - .mixers = { alc861vd_dallas_mixer }, - .init_verbs = { alc861vd_dallas_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_dallas_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc861vd_dallas_setup, - .init_hook = alc_hp_automute, - }, - [ALC861VD_HP] = { - .mixers = { alc861vd_hp_mixer }, - .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_hp_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc861vd_dallas_setup, - .init_hook = alc_hp_automute, - }, - [ALC660VD_ASUS_V1S] = { - .mixers = { alc861vd_lenovo_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs, - alc861vd_eapd_verbs, - alc861vd_lenovo_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - .unsol_event = alc861vd_lenovo_unsol_event, - .setup = alc861vd_lenovo_setup, - .init_hook = alc861vd_lenovo_init_hook, - }, -}; - diff --git a/trunk/sound/pci/hda/alc880_quirks.c b/trunk/sound/pci/hda/alc880_quirks.c deleted file mode 100644 index c844d2b59988..000000000000 --- a/trunk/sound/pci/hda/alc880_quirks.c +++ /dev/null @@ -1,1898 +0,0 @@ -/* - * ALC880 quirk models - * included by patch_realtek.c - */ - -/* ALC880 board config type */ -enum { - ALC880_AUTO, - ALC880_3ST, - ALC880_3ST_DIG, - ALC880_5ST, - ALC880_5ST_DIG, - ALC880_W810, - ALC880_Z71V, - ALC880_6ST, - ALC880_6ST_DIG, - ALC880_F1734, - ALC880_ASUS, - ALC880_ASUS_DIG, - ALC880_ASUS_W1V, - ALC880_ASUS_DIG2, - ALC880_FUJITSU, - ALC880_UNIWILL_DIG, - ALC880_UNIWILL, - ALC880_UNIWILL_P53, - ALC880_CLEVO, - ALC880_TCL_S700, - ALC880_LG, - ALC880_LG_LW, - ALC880_MEDION_RIM, -#ifdef CONFIG_SND_DEBUG - ALC880_TEST, -#endif - ALC880_MODEL_LAST /* last tag */ -}; - -/* - * ALC880 3-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) - * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, - * F-Mic = 0x1b, HP = 0x19 - */ - -static const hda_nid_t alc880_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x05, 0x04, 0x03 -}; - -static const hda_nid_t alc880_adc_nids[3] = { - /* ADC0-2 */ - 0x07, 0x08, 0x09, -}; - -/* The datasheet says the node 0x07 is connected from inputs, - * but it shows zero connection in the real implementation on some devices. - * Note: this is a 915GAV bug, fixed on 915GLV - */ -static const hda_nid_t alc880_adc_nids_alt[2] = { - /* ADC1-2 */ - 0x08, 0x09, -}; - -#define ALC880_DIGOUT_NID 0x06 -#define ALC880_DIGIN_NID 0x0a -#define ALC880_PIN_CD_NID 0x1c - -static const struct hda_input_mux alc880_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* channel source setting (2/6 channel selection for 3-stack) */ -/* 2ch mode */ -static const struct hda_verb alc880_threestack_ch2_init[] = { - /* set line-in to input, mute it */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - /* set mic-in to input vref 80%, mute it */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* 6ch mode */ -static const struct hda_verb alc880_threestack_ch6_init[] = { - /* set line-in to output, unmute it */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - /* set mic-in to output, unmute it */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static const struct hda_channel_mode alc880_threestack_modes[2] = { - { 2, alc880_threestack_ch2_init }, - { 6, alc880_threestack_ch6_init }, -}; - -static const struct snd_kcontrol_new alc880_three_stack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* - * ALC880 5-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), - * Side = 0x02 (0xd) - * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 - * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 - */ - -/* additional mixers to alc880_three_stack_mixer */ -static const struct snd_kcontrol_new alc880_five_stack_mixer[] = { - HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), - { } /* end */ -}; - -/* channel source setting (6/8 channel selection for 5-stack) */ -/* 6ch mode */ -static const struct hda_verb alc880_fivestack_ch6_init[] = { - /* set line-in to input, mute it */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* 8ch mode */ -static const struct hda_verb alc880_fivestack_ch8_init[] = { - /* set line-in to output, unmute it */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static const struct hda_channel_mode alc880_fivestack_modes[2] = { - { 6, alc880_fivestack_ch6_init }, - { 8, alc880_fivestack_ch8_init }, -}; - - -/* - * ALC880 6-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), - * Side = 0x05 (0x0f) - * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, - * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b - */ - -static const hda_nid_t alc880_6st_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -static const struct hda_input_mux alc880_6stack_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* fixed 8-channels */ -static const struct hda_channel_mode alc880_sixstack_modes[1] = { - { 8, NULL }, -}; - -static const struct snd_kcontrol_new alc880_six_stack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - - -/* - * ALC880 W810 model - * - * W810 has rear IO for: - * Front (DAC 02) - * Surround (DAC 03) - * Center/LFE (DAC 04) - * Digital out (06) - * - * The system also has a pair of internal speakers, and a headphone jack. - * These are both connected to Line2 on the codec, hence to DAC 02. - * - * There is a variable resistor to control the speaker or headphone - * volume. This is a hardware-only device without a software API. - * - * Plugging headphones in will disable the internal speakers. This is - * implemented in hardware, not via the driver using jack sense. In - * a similar fashion, plugging into the rear socket marked "front" will - * disable both the speakers and headphones. - * - * For input, there's a microphone jack, and an "audio in" jack. - * These may not do anything useful with this driver yet, because I - * haven't setup any initialization verbs for these yet... - */ - -static const hda_nid_t alc880_w810_dac_nids[3] = { - /* front, rear/surround, clfe */ - 0x02, 0x03, 0x04 -}; - -/* fixed 6 channels */ -static const struct hda_channel_mode alc880_w810_modes[1] = { - { 6, NULL } -}; - -/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ -static const struct snd_kcontrol_new alc880_w810_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - { } /* end */ -}; - - -/* - * Z710V model - * - * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) - * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), - * Line = 0x1a - */ - -static const hda_nid_t alc880_z71v_dac_nids[1] = { - 0x02 -}; -#define ALC880_Z71V_HP_DAC 0x03 - -/* fixed 2 channels */ -static const struct hda_channel_mode alc880_2_jack_modes[1] = { - { 2, NULL } -}; - -static const struct snd_kcontrol_new alc880_z71v_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - - -/* - * ALC880 F1734 model - * - * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) - * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 - */ - -static const hda_nid_t alc880_f1734_dac_nids[1] = { - 0x03 -}; -#define ALC880_F1734_HP_DAC 0x02 - -static const struct snd_kcontrol_new alc880_f1734_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_input_mux alc880_f1734_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "CD", 0x4 }, - }, -}; - - -/* - * ALC880 ASUS model - * - * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) - * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, - * Mic = 0x18, Line = 0x1a - */ - -#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ -#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ - -static const struct snd_kcontrol_new alc880_asus_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* - * ALC880 ASUS W1V model - * - * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) - * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, - * Mic = 0x18, Line = 0x1a, Line2 = 0x1b - */ - -/* additional mixers to alc880_asus_mixer */ -static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { - HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), - { } /* end */ -}; - -/* TCL S700 */ -static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* Uniwill */ -static const struct snd_kcontrol_new alc880_uniwill_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* - * initialize the codec volumes, etc - */ - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc880_volume_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for front - * panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - { } -}; - -/* - * 3-stack pin configuration: - * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b - */ -static const struct hda_verb alc880_pin_3stack_init_verbs[] = { - /* - * preset connection lists of input pins - * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround - */ - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ - - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mic2 (as headphone out) for HP output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line2 (as front mic) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 5-stack pin configuration: - * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, - * line-in/side = 0x1a, f-mic = 0x1b - */ -static const struct hda_verb alc880_pin_5stack_init_verbs[] = { - /* - * preset connection lists of input pins - * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround - */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ - - /* - * Set pin mode and muting - */ - /* set pin widgets 0x14-0x17 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* unmute pins for output (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mic2 (as headphone out) for HP output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line2 (as front mic) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * W810 pin configuration: - * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b - */ -static const struct hda_verb alc880_pin_w810_init_verbs[] = { - /* hphone/speaker input selector: front DAC */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - { } -}; - -/* - * Z71V pin configuration: - * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) - */ -static const struct hda_verb alc880_pin_z71v_init_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 6-stack pin configuration: - * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, - * f-mic = 0x19, line = 0x1a, HP = 0x1b - */ -static const struct hda_verb alc880_pin_6stack_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * Uniwill pin configuration: - * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, - * line = 0x1a - */ -static const struct hda_verb alc880_uniwill_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */ - /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - - { } -}; - -/* -* Uniwill P53 -* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, - */ -static const struct hda_verb alc880_uniwill_p53_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_DCVOL_EVENT}, - - { } -}; - -static const struct hda_verb alc880_beep_init_verbs[] = { - { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, - { } -}; - -static void alc880_uniwill_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc880_uniwill_init_hook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc88x_simple_mic_automute(codec); -} - -static void alc880_uniwill_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - switch (res >> 28) { - case ALC_MIC_EVENT: - alc88x_simple_mic_automute(codec); - break; - default: - alc_sku_unsol_event(codec, res); - break; - } -} - -static void alc880_uniwill_p53_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); - present &= HDA_AMP_VOLMASK; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, present); - snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, present); -} - -static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - if ((res >> 28) == ALC_DCVOL_EVENT) - alc880_uniwill_p53_dcvol_automute(codec); - else - alc_sku_unsol_event(codec, res); -} - -/* - * F1734 pin configuration: - * HP = 0x14, speaker-out = 0x15, mic = 0x18 - */ -static const struct hda_verb alc880_pin_f1734_init_verbs[] = { - {0x07, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_DCVOL_EVENT}, - - { } -}; - -/* - * ASUS pin configuration: - * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a - */ -static const struct hda_verb alc880_pin_asus_init_verbs[] = { - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* Enable GPIO mask and set output */ -#define alc880_gpio1_init_verbs alc_gpio1_init_verbs -#define alc880_gpio2_init_verbs alc_gpio2_init_verbs -#define alc880_gpio3_init_verbs alc_gpio3_init_verbs - -/* Clevo m520g init */ -static const struct hda_verb alc880_pin_clevo_init_verbs[] = { - /* headphone output */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* line-out */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line-in */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* CD */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic1 (rear panel) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic2 (front panel) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* headphone */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - - { } -}; - -static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - - /* Headphone output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Front output*/ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, - - { } -}; - -/* - * LG m1 express dual - * - * Pin assignment: - * Rear Line-In/Out (blue): 0x14 - * Build-in Mic-In: 0x15 - * Speaker-out: 0x17 - * HP-Out (green): 0x1b - * Mic-In/Out (red): 0x19 - * SPDIF-Out: 0x1e - */ - -/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */ -static const hda_nid_t alc880_lg_dac_nids[3] = { - 0x05, 0x02, 0x03 -}; - -/* seems analog CD is not working */ -static const struct hda_input_mux alc880_lg_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x1 }, - { "Line", 0x5 }, - { "Internal Mic", 0x6 }, - }, -}; - -/* 2,4,6 channel modes */ -static const struct hda_verb alc880_lg_ch2_init[] = { - /* set line-in and mic-in to input */ - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { } -}; - -static const struct hda_verb alc880_lg_ch4_init[] = { - /* set line-in to out and mic-in to input */ - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { } -}; - -static const struct hda_verb alc880_lg_ch6_init[] = { - /* set line-in and mic-in to output */ - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { } -}; - -static const struct hda_channel_mode alc880_lg_ch_modes[3] = { - { 2, alc880_lg_ch2_init }, - { 4, alc880_lg_ch4_init }, - { 6, alc880_lg_ch6_init }, -}; - -static const struct snd_kcontrol_new alc880_lg_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc880_lg_init_verbs[] = { - /* set capture source to mic-in */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* mute all amp mixer inputs */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* line-in to input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* built-in mic */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* speaker-out */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* mic-in to input */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* HP-out */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x03}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* - * LG LW20 - * - * Pin assignment: - * Speaker-out: 0x14 - * Mic-In: 0x18 - * Built-in Mic-In: 0x19 - * Line-In: 0x1b - * HP-Out: 0x1a - * SPDIF-Out: 0x1e - */ - -static const struct hda_input_mux alc880_lg_lw_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Line In", 0x2 }, - }, -}; - -#define alc880_lg_lw_modes alc880_threestack_modes - -static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc880_lg_lw_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ - - /* set capture source to mic-in */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* speaker-out */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* HP-out */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* mic-in to input */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* built-in mic */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_lw_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_input_mux alc880_medion_rim_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - }, -}; - -static const struct hda_verb alc880_medion_rim_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mic2 (as headphone out) for HP output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Internal Speaker */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc880_medion_rim_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - alc_hp_automute(codec); - /* toggle EAPD */ - if (spec->jack_present) - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); - else - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2); -} - -static void alc880_medion_rim_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - if ((res >> 28) == ALC_HP_EVENT) - alc880_medion_rim_automute(codec); -} - -static void alc880_medion_rim_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -#ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc880_lg_loopbacks[] = { - { 0x0b, HDA_INPUT, 1 }, - { 0x0b, HDA_INPUT, 6 }, - { 0x0b, HDA_INPUT, 7 }, - { } /* end */ -}; -#endif - -/* - * Test configuration for debugging - * - * Almost all inputs/outputs are enabled. I/O pins can be configured via - * enum controls. - */ -#ifdef CONFIG_SND_DEBUG -static const hda_nid_t alc880_test_dac_nids[4] = { - 0x02, 0x03, 0x04, 0x05 -}; - -static const struct hda_input_mux alc880_test_capture_source = { - .num_items = 7, - .items = { - { "In-1", 0x0 }, - { "In-2", 0x1 }, - { "In-3", 0x2 }, - { "In-4", 0x3 }, - { "CD", 0x4 }, - { "Front", 0x5 }, - { "Surround", 0x6 }, - }, -}; - -static const struct hda_channel_mode alc880_test_modes[4] = { - { 2, NULL }, - { 4, NULL }, - { 6, NULL }, - { 8, NULL }, -}; - -static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { - "N/A", "Line Out", "HP Out", - "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item >= 8) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int pin_ctl, item = 0; - - pin_ctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pin_ctl & AC_PINCTL_OUT_EN) { - if (pin_ctl & AC_PINCTL_HP_EN) - item = 2; - else - item = 1; - } else if (pin_ctl & AC_PINCTL_IN_EN) { - switch (pin_ctl & AC_PINCTL_VREFEN) { - case AC_PINCTL_VREF_HIZ: item = 3; break; - case AC_PINCTL_VREF_50: item = 4; break; - case AC_PINCTL_VREF_GRD: item = 5; break; - case AC_PINCTL_VREF_80: item = 6; break; - case AC_PINCTL_VREF_100: item = 7; break; - } - } - ucontrol->value.enumerated.item[0] = item; - return 0; -} - -static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - static const unsigned int ctls[] = { - 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, - }; - unsigned int old_ctl, new_ctl; - - old_ctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - new_ctl = ctls[ucontrol->value.enumerated.item[0]]; - if (old_ctl != new_ctl) { - int val; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - new_ctl); - val = ucontrol->value.enumerated.item[0] >= 3 ? - HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, val); - return 1; - } - return 0; -} - -static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { - "Front", "Surround", "CLFE", "Side" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int sel; - - sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); - ucontrol->value.enumerated.item[0] = sel & 3; - return 0; -} - -static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int sel; - - sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; - if (ucontrol->value.enumerated.item[0] != sel) { - sel = ucontrol->value.enumerated.item[0] & 3; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, sel); - return 1; - } - return 0; -} - -#define PIN_CTL_TEST(xname,nid) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_test_pin_ctl_info, \ - .get = alc_test_pin_ctl_get, \ - .put = alc_test_pin_ctl_put, \ - .private_value = nid \ - } - -#define PIN_SRC_TEST(xname,nid) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_test_pin_src_info, \ - .get = alc_test_pin_src_get, \ - .put = alc_test_pin_src_put, \ - .private_value = nid \ - } - -static const struct snd_kcontrol_new alc880_test_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - PIN_CTL_TEST("Front Pin Mode", 0x14), - PIN_CTL_TEST("Surround Pin Mode", 0x15), - PIN_CTL_TEST("CLFE Pin Mode", 0x16), - PIN_CTL_TEST("Side Pin Mode", 0x17), - PIN_CTL_TEST("In-1 Pin Mode", 0x18), - PIN_CTL_TEST("In-2 Pin Mode", 0x19), - PIN_CTL_TEST("In-3 Pin Mode", 0x1a), - PIN_CTL_TEST("In-4 Pin Mode", 0x1b), - PIN_SRC_TEST("In-1 Pin Source", 0x18), - PIN_SRC_TEST("In-2 Pin Source", 0x19), - PIN_SRC_TEST("In-3 Pin Source", 0x1a), - PIN_SRC_TEST("In-4 Pin Source", 0x1b), - HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc880_test_init_verbs[] = { - /* Unmute inputs of 0x0c - 0x0f */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Vol output for 0x0c-0x0f */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Set output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Unmute output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Set input pins 0x18-0x1c */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mute input pins 0x18-0x1b */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* ADC set up */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Analog input/passthru */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - { } -}; -#endif - -/* - */ - -static const char * const alc880_models[ALC880_MODEL_LAST] = { - [ALC880_3ST] = "3stack", - [ALC880_TCL_S700] = "tcl", - [ALC880_3ST_DIG] = "3stack-digout", - [ALC880_CLEVO] = "clevo", - [ALC880_5ST] = "5stack", - [ALC880_5ST_DIG] = "5stack-digout", - [ALC880_W810] = "w810", - [ALC880_Z71V] = "z71v", - [ALC880_6ST] = "6stack", - [ALC880_6ST_DIG] = "6stack-digout", - [ALC880_ASUS] = "asus", - [ALC880_ASUS_W1V] = "asus-w1v", - [ALC880_ASUS_DIG] = "asus-dig", - [ALC880_ASUS_DIG2] = "asus-dig2", - [ALC880_UNIWILL_DIG] = "uniwill", - [ALC880_UNIWILL_P53] = "uniwill-p53", - [ALC880_FUJITSU] = "fujitsu", - [ALC880_F1734] = "F1734", - [ALC880_LG] = "lg", - [ALC880_LG_LW] = "lg-lw", - [ALC880_MEDION_RIM] = "medion", -#ifdef CONFIG_SND_DEBUG - [ALC880_TEST] = "test", -#endif - [ALC880_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc880_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), - SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), - SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), - SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), - SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V), - /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */ - SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), - SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), - SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */ - SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), - SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), - SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), - SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), - SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), - SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), - SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734), - SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), - SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), - SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), - SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM), - SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), - SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), - SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734), - SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), - SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), - SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), - SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG), - SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), - SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), - SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), - SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */ - SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), - SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), - /* default Intel */ - SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST), - SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), - SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), - {} -}; - -/* - * ALC880 codec presets - */ -static const struct alc_config_preset alc880_presets[] = { - [ALC880_3ST] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_3ST_DIG] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_TCL_S700] = { - .mixers = { alc880_tcl_s700_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_tcl_S700_init_verbs, - alc880_gpio2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */ - .num_adc_nids = 1, /* single ADC */ - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_5ST] = { - .mixers = { alc880_three_stack_mixer, - alc880_five_stack_mixer}, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_5stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), - .channel_mode = alc880_fivestack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_5ST_DIG] = { - .mixers = { alc880_three_stack_mixer, - alc880_five_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_5stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), - .channel_mode = alc880_fivestack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_6ST] = { - .mixers = { alc880_six_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), - .dac_nids = alc880_6st_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), - .channel_mode = alc880_sixstack_modes, - .input_mux = &alc880_6stack_capture_source, - }, - [ALC880_6ST_DIG] = { - .mixers = { alc880_six_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), - .dac_nids = alc880_6st_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), - .channel_mode = alc880_sixstack_modes, - .input_mux = &alc880_6stack_capture_source, - }, - [ALC880_W810] = { - .mixers = { alc880_w810_base_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_w810_init_verbs, - alc880_gpio2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), - .dac_nids = alc880_w810_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), - .channel_mode = alc880_w810_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_Z71V] = { - .mixers = { alc880_z71v_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_z71v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), - .dac_nids = alc880_z71v_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_F1734] = { - .mixers = { alc880_f1734_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_f1734_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), - .dac_nids = alc880_f1734_dac_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_f1734_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_ASUS] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_DIG] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_DIG2] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio2_init_verbs }, /* use GPIO2 */ - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_W1V] = { - .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_UNIWILL_DIG] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_UNIWILL] = { - .mixers = { alc880_uniwill_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_unsol_event, - .setup = alc880_uniwill_setup, - .init_hook = alc880_uniwill_init_hook, - }, - [ALC880_UNIWILL_P53] = { - .mixers = { alc880_uniwill_p53_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_p53_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), - .channel_mode = alc880_threestack_modes, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_FUJITSU] = { - .mixers = { alc880_fujitsu_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_p53_init_verbs, - alc880_beep_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_CLEVO] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_clevo_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_LG] = { - .mixers = { alc880_lg_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_lg_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids), - .dac_nids = alc880_lg_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), - .channel_mode = alc880_lg_ch_modes, - .need_dac_fix = 1, - .input_mux = &alc880_lg_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc880_lg_setup, - .init_hook = alc_hp_automute, -#ifdef CONFIG_SND_HDA_POWER_SAVE - .loopbacks = alc880_lg_loopbacks, -#endif - }, - [ALC880_LG_LW] = { - .mixers = { alc880_lg_lw_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_lg_lw_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), - .channel_mode = alc880_lg_lw_modes, - .input_mux = &alc880_lg_lw_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc880_lg_lw_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_MEDION_RIM] = { - .mixers = { alc880_medion_rim_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_medion_rim_init_verbs, - alc_gpio2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_medion_rim_capture_source, - .unsol_event = alc880_medion_rim_unsol_event, - .setup = alc880_medion_rim_setup, - .init_hook = alc880_medion_rim_automute, - }, -#ifdef CONFIG_SND_DEBUG - [ALC880_TEST] = { - .mixers = { alc880_test_mixer }, - .init_verbs = { alc880_test_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), - .dac_nids = alc880_test_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_test_modes), - .channel_mode = alc880_test_modes, - .input_mux = &alc880_test_capture_source, - }, -#endif -}; - diff --git a/trunk/sound/pci/hda/alc882_quirks.c b/trunk/sound/pci/hda/alc882_quirks.c deleted file mode 100644 index 617d04723b82..000000000000 --- a/trunk/sound/pci/hda/alc882_quirks.c +++ /dev/null @@ -1,3755 +0,0 @@ -/* - * ALC882/ALC883/ALC888/ALC889 quirk models - * included by patch_realtek.c - */ - -/* ALC882 models */ -enum { - ALC882_AUTO, - ALC882_3ST_DIG, - ALC882_6ST_DIG, - ALC882_ARIMA, - ALC882_W2JC, - ALC882_TARGA, - ALC882_ASUS_A7J, - ALC882_ASUS_A7M, - ALC885_MACPRO, - ALC885_MBA21, - ALC885_MBP3, - ALC885_MB5, - ALC885_MACMINI3, - ALC885_IMAC24, - ALC885_IMAC91, - ALC883_3ST_2ch_DIG, - ALC883_3ST_6ch_DIG, - ALC883_3ST_6ch, - ALC883_6ST_DIG, - ALC883_TARGA_DIG, - ALC883_TARGA_2ch_DIG, - ALC883_TARGA_8ch_DIG, - ALC883_ACER, - ALC883_ACER_ASPIRE, - ALC888_ACER_ASPIRE_4930G, - ALC888_ACER_ASPIRE_6530G, - ALC888_ACER_ASPIRE_8930G, - ALC888_ACER_ASPIRE_7730G, - ALC883_MEDION, - ALC883_MEDION_WIM2160, - ALC883_LAPTOP_EAPD, - ALC883_LENOVO_101E_2ch, - ALC883_LENOVO_NB0763, - ALC888_LENOVO_MS7195_DIG, - ALC888_LENOVO_SKY, - ALC883_HAIER_W66, - ALC888_3ST_HP, - ALC888_6ST_DELL, - ALC883_MITAC, - ALC883_CLEVO_M540R, - ALC883_CLEVO_M720, - ALC883_FUJITSU_PI2515, - ALC888_FUJITSU_XA3530, - ALC883_3ST_6ch_INTEL, - ALC889A_INTEL, - ALC889_INTEL, - ALC888_ASUS_M90V, - ALC888_ASUS_EEE1601, - ALC889A_MB31, - ALC1200_ASUS_P5Q, - ALC883_SONY_VAIO_TT, - ALC882_MODEL_LAST, -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc888_4ST_ch2_intel_init[] = { -/* Mic-in jack as mic in */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, -/* Line-in jack as Line in */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, -/* Line-Out as Front */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc888_4ST_ch4_intel_init[] = { -/* Mic-in jack as mic in */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, -/* Line-in jack as Surround */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-Out as Front */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc888_4ST_ch6_intel_init[] = { -/* Mic-in jack as CLFE */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-in jack as Surround */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc888_4ST_ch8_intel_init[] = { -/* Mic-in jack as CLFE */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-in jack as Surround */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-Out as Side */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - { } /* end */ -}; - -static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { - { 2, alc888_4ST_ch2_intel_init }, - { 4, alc888_4ST_ch4_intel_init }, - { 6, alc888_4ST_ch6_intel_init }, - { 8, alc888_4ST_ch8_intel_init }, -}; - -/* - * ALC888 Fujitsu Siemens Amillo xa3530 - */ - -static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = { -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Connect Internal HP to Front */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect Bass HP to Front */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect Line-Out side jack (SPDIF) to Side */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, -/* Connect Mic jack to CLFE */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, -/* Connect Line-in jack to Surround */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, -/* Connect HP out jack to Front */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Enable unsolicited event for HP jack and Line-out jack */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {} -}; - -static void alc889_automute_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x17; - spec->autocfg.speaker_pins[3] = 0x19; - spec->autocfg.speaker_pins[4] = 0x1a; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc889_intel_init_hook(struct hda_codec *codec) -{ - alc889_coef_init(codec); - alc_hp_automute(codec); -} - -static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x17; /* line-out */ - spec->autocfg.hp_pins[1] = 0x1b; /* hp */ - spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ - spec->autocfg.speaker_pins[1] = 0x15; /* bass */ - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* - * ALC888 Acer Aspire 4930G model - */ - -static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = { -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Unselect Front Mic by default in input mixer 3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, -/* Connect Internal HP to front */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect HP out to front */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* - * ALC888 Acer Aspire 6530G model - */ - -static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = { -/* Route to built-in subwoofer as well as speakers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, -/* Bias voltage on for external mic port */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Unselect Front Mic by default in input mixer 3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, -/* Enable speaker output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, -/* Enable headphone output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* - *ALC888 Acer Aspire 7730G model - */ - -static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = { -/* Bias voltage on for external mic port */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Unselect Front Mic by default in input mixer 3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, -/* Enable speaker output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, -/* Enable headphone output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, -/*Enable internal subwoofer */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* - * ALC889 Acer Aspire 8930G model - */ - -static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = { -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Unselect Front Mic by default in input mixer 3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, -/* Connect Internal Front to Front */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect Internal Rear to Rear */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, -/* Connect Internal CLFE to CLFE */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, -/* Connect HP out to Front */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Enable all DACs */ -/* DAC DISABLE/MUTE 1? */ -/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x03}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, -/* DAC DISABLE/MUTE 2? */ -/* some bit here disables the other DACs. Init=0x4900 */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x08}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, -/* DMIC fix - * This laptop has a stereo digital microphone. The mics are only 1cm apart - * which makes the stereo useless. However, either the mic or the ALC889 - * makes the signal become a difference/sum signal instead of standard - * stereo, which is annoying. So instead we flip this bit which makes the - * codec replicate the sum signal to both channels, turning it into a - * normal mono mic. - */ -/* DMIC_CONTROL? Init value = 0x0001 */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0003}, - { } -}; - -static const struct hda_input_mux alc888_2_capture_sources[2] = { - /* Front mic only available on one ADC */ - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Front Mic", 0xb }, - }, - }, - { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, - } -}; - -static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { - /* Interal mic only available on one ADC */ - { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Line In", 0x2 }, - { "CD", 0x4 }, - { "Input Mix", 0xa }, - { "Internal Mic", 0xb }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line In", 0x2 }, - { "CD", 0x4 }, - { "Input Mix", 0xa }, - }, - } -}; - -static const struct hda_input_mux alc889_capture_sources[3] = { - /* Digital mic only available on first "ADC" */ - { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Front Mic", 0xb }, - { "Input Mix", 0xa }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Input Mix", 0xa }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Input Mix", 0xa }, - }, - } -}; - -static const struct snd_kcontrol_new alc888_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - - -static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -#define ALC882_DIGOUT_NID 0x06 -#define ALC882_DIGIN_NID 0x0a -#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID -#define ALC883_DIGIN_NID ALC882_DIGIN_NID -#define ALC1200_DIGOUT_NID 0x10 - - -static const struct hda_channel_mode alc882_ch_modes[1] = { - { 8, NULL } -}; - -/* DACs */ -static const hda_nid_t alc882_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; -#define alc883_dac_nids alc882_dac_nids - -/* ADCs */ -#define alc882_adc_nids alc880_adc_nids -#define alc882_adc_nids_alt alc880_adc_nids_alt -#define alc883_adc_nids alc882_adc_nids_alt -static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 }; -static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 }; -#define alc889_adc_nids alc880_adc_nids - -static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 }; -static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; -#define alc883_capsrc_nids alc882_capsrc_nids_alt -static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; -#define alc889_capsrc_nids alc882_capsrc_nids - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ - -static const struct hda_input_mux alc882_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -#define alc883_capture_source alc882_capture_source - -static const struct hda_input_mux alc889_capture_source = { - .num_items = 3, - .items = { - { "Front Mic", 0x0 }, - { "Mic", 0x3 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux mb5_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x1 }, - { "Line", 0x7 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux macmini3_capture_source = { - .num_items = 2, - .items = { - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc883_3stack_6ch_intel = { - .num_items = 4, - .items = { - { "Mic", 0x1 }, - { "Front Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc883_lenovo_101e_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - }, -}; - -static const struct hda_input_mux alc883_lenovo_sky_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x4 }, - }, -}; - -static const struct hda_input_mux alc883_asus_eee1601_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux alc889A_mb31_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - /* Front Mic (0x01) unused */ - { "Line", 0x2 }, - /* Line 2 (0x03) unused */ - /* CD (0x04) unused? */ - }, -}; - -static const struct hda_input_mux alc889A_imac91_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x01 }, - { "Line", 0x2 }, /* Not sure! */ - }, -}; - -/* - * 2ch mode - */ -static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc882_3ST_ch2_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc882_3ST_ch4_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc882_3ST_ch6_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = { - { 2, alc882_3ST_ch2_init }, - { 4, alc882_3ST_ch4_init }, - { 6, alc882_3ST_ch6_init }, -}; - -#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes - -/* - * 2ch mode - */ -static const struct hda_verb alc883_3ST_ch2_clevo_init[] = { - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc883_3ST_ch4_clevo_init[] = { - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc883_3ST_ch6_clevo_init[] = { - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { - { 2, alc883_3ST_ch2_clevo_init }, - { 4, alc883_3ST_ch4_clevo_init }, - { 6, alc883_3ST_ch6_clevo_init }, -}; - - -/* - * 6ch mode - */ -static const struct hda_verb alc882_sixstack_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc882_sixstack_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static const struct hda_channel_mode alc882_sixstack_modes[2] = { - { 6, alc882_sixstack_ch6_init }, - { 8, alc882_sixstack_ch8_init }, -}; - - -/* Macbook Air 2,1 */ - -static const struct hda_channel_mode alc885_mba21_ch_modes[1] = { - { 2, NULL }, -}; - -/* - * macbook pro ALC885 can switch LineIn to LineOut without losing Mic - */ - -/* - * 2ch mode - */ -static const struct hda_verb alc885_mbp_ch2_init[] = { - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc885_mbp_ch4_init[] = { - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - { } /* end */ -}; - -static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = { - { 2, alc885_mbp_ch2_init }, - { 4, alc885_mbp_ch4_init }, -}; - -/* - * 2ch - * Speakers/Woofer/HP = Front - * LineIn = Input - */ -static const struct hda_verb alc885_mb5_ch2_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - { } /* end */ -}; - -/* - * 6ch mode - * Speakers/HP = Front - * Woofer = LFE - * LineIn = Surround - */ -static const struct hda_verb alc885_mb5_ch6_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - { } /* end */ -}; - -static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = { - { 2, alc885_mb5_ch2_init }, - { 6, alc885_mb5_ch6_init }, -}; - -#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes - -/* - * 2ch mode - */ -static const struct hda_verb alc883_4ST_ch2_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc883_4ST_ch4_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc883_4ST_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc883_4ST_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = { - { 2, alc883_4ST_ch2_init }, - { 4, alc883_4ST_ch4_init }, - { 6, alc883_4ST_ch6_init }, - { 8, alc883_4ST_ch8_init }, -}; - - -/* - * 2ch mode - */ -static const struct hda_verb alc883_3ST_ch2_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc883_3ST_ch4_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc883_3ST_ch6_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { - { 2, alc883_3ST_ch2_intel_init }, - { 4, alc883_3ST_ch4_intel_init }, - { 6, alc883_3ST_ch6_intel_init }, -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc889_ch2_intel_init[] = { - { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc889_ch6_intel_init[] = { - { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc889_ch8_intel_init[] = { - { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static const struct hda_channel_mode alc889_8ch_intel_modes[3] = { - { 2, alc889_ch2_intel_init }, - { 6, alc889_ch6_intel_init }, - { 8, alc889_ch8_intel_init }, -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc883_sixstack_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc883_sixstack_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static const struct hda_channel_mode alc883_sixstack_modes[2] = { - { 6, alc883_sixstack_ch6_init }, - { 8, alc883_sixstack_ch8_init }, -}; - - -/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 - * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b - */ -static const struct snd_kcontrol_new alc882_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -/* Macbook Air 2,1 same control for HP and internal Speaker */ - -static const struct snd_kcontrol_new alc885_mba21_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT), - { } -}; - - -static const struct snd_kcontrol_new alc885_mbp3_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc885_mb5_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc885_macmini3_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc885_imac91_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), - { } /* end */ -}; - - -static const struct snd_kcontrol_new alc882_w2jc_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc882_targa_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ??? - * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c - */ -static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc882_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc882_base_init_verbs[] = { - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Rear Pin: output 1 (0x0d) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - { } -}; - -static const struct hda_verb alc882_adc1_init_verbs[] = { - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* ADC1: mute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } -}; - -static const struct hda_verb alc882_eapd_verbs[] = { - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - { } -}; - -static const struct hda_verb alc889_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc_hp15_unsol_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -static const struct hda_verb alc885_init_verbs[] = { - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Front HP Pin: output 0 (0x0c) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Rear Pin: output 1 (0x0d) */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic (rear) pin: input vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* Mixer elements: 0x18, , 0x1a, 0x1b */ - /* Input mixer1 */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - { } -}; - -static const struct hda_verb alc885_init_input_verbs[] = { - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - { } -}; - - -/* Unmute Selector 24h and set the default input to front mic */ -static const struct hda_verb alc889_init_input_verbs[] = { - {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - { } -}; - - -#define alc883_init_verbs alc882_base_init_verbs - -/* Mac Pro test */ -static const struct snd_kcontrol_new alc882_macpro_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), - /* FIXME: this looks suspicious... - HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT), - */ - { } /* end */ -}; - -static const struct hda_verb alc882_macpro_init_verbs[] = { - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin: output 0 (0x0c) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Speaker: output */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04}, - /* Headphone output (output 0 - 0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* ADC1: mute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - { } -}; - -/* Macbook 5,1 */ -static const struct hda_verb alc885_mb5_init_verbs[] = { - /* DACs */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Front mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Surround mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* LFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* HP mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LFE Pin (0x0e) */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* HP Pin (0x0f) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)}, - { } -}; - -/* Macmini 3,1 */ -static const struct hda_verb alc885_macmini3_init_verbs[] = { - /* DACs */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Front mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Surround mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* LFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* HP mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LFE Pin (0x0e) */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* HP Pin (0x0f) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Line In pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - { } -}; - - -static const struct hda_verb alc885_mba21_init_verbs[] = { - /*Internal and HP Speaker Mixer*/ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /*Internal Speaker Pin (0x0c)*/ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP Pin: output 0 (0x0e) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)}, - /* Line in (is hp when jack connected)*/ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - { } - }; - - -/* Macbook Pro rev3 */ -static const struct hda_verb alc885_mbp3_init_verbs[] = { - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* HP mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP Pin: output 0 (0x0e) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: use output 1 when in LineOut mode */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* ADC1: mute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - { } -}; - -/* iMac 9,1 */ -static const struct hda_verb alc885_imac91_init_verbs[] = { - /* Internal Speaker Pin (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP Pin: Rear */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)}, - /* Line in Rear */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } -}; - -/* iMac 24 mixer. */ -static const struct snd_kcontrol_new alc885_imac24_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT), - { } /* end */ -}; - -/* iMac 24 init verbs. */ -static const struct hda_verb alc885_imac24_init_verbs[] = { - /* Internal speakers: output 0 (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Internal speakers: output 0 (0x0c) */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Headphone: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Front Mic: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - { } -}; - -/* Toggle speaker-output according to the hp-jack state */ -static void alc885_imac24_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - spec->autocfg.speaker_pins[1] = 0x1a; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -#define alc885_mb5_setup alc885_imac24_setup -#define alc885_macmini3_setup alc885_imac24_setup - -/* Macbook Air 2,1 */ -static void alc885_mba21_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - - - -static void alc885_mbp3_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc885_imac91_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - spec->autocfg.speaker_pins[1] = 0x1a; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc882_targa_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc882_targa_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - alc_hp_automute(codec); - snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - spec->jack_present ? 1 : 3); -} - -static void alc882_targa_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc882_targa_automute(codec); -} - -static const struct hda_verb alc882_asus_a7j_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ - - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - { } /* end */ -}; - -static const struct hda_verb alc882_asus_a7m_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ - - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - { } /* end */ -}; - -static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) -{ - unsigned int gpiostate, gpiomask, gpiodir; - - gpiostate = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - - if (!muted) - gpiostate |= (1 << pin); - else - gpiostate &= ~(1 << pin); - - gpiomask = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_MASK, 0); - gpiomask |= (1 << pin); - - gpiodir = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DIRECTION, 0); - gpiodir |= (1 << pin); - - - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, gpiomask); - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, gpiodir); - - msleep(1); - - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, gpiostate); -} - -/* set up GPIO at initialization */ -static void alc885_macpro_init_hook(struct hda_codec *codec) -{ - alc882_gpio_mute(codec, 0, 0); - alc882_gpio_mute(codec, 1, 0); -} - -/* set up GPIO and update auto-muting at initialization */ -static void alc885_imac24_init_hook(struct hda_codec *codec) -{ - alc885_macpro_init_hook(codec); - alc_hp_automute(codec); -} - -/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ -static const struct hda_verb alc889A_mb31_ch2_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ - { } /* end */ -}; - -/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ -static const struct hda_verb alc889A_mb31_ch4_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ - { } /* end */ -}; - -/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ -static const struct hda_verb alc889A_mb31_ch5_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ - { } /* end */ -}; - -/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ -static const struct hda_verb alc889A_mb31_ch6_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ - { } /* end */ -}; - -static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { - { 2, alc889A_mb31_ch2_init }, - { 4, alc889A_mb31_ch4_init }, - { 5, alc889A_mb31_ch5_init }, - { 6, alc889A_mb31_ch6_init }, -}; - -static const struct hda_verb alc883_medion_eapd_verbs[] = { - /* eanable EAPD on medion laptop */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, - { } -}; - -#define alc883_base_mixer alc882_base_mixer - -static const struct snd_kcontrol_new alc883_mitac_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_fivestack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_targa_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb alc883_medion_wim2160_verbs[] = { - /* Unmute front mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Set speaker pin to front mixer */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Init headphone pin */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } /* end */ -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_medion_wim2160_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1a; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", - 0x0d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc889A_mb31_mixer[] = { - /* Output mixers */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT), - /* Output switches */ - HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT), - /* Boost mixers */ - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), - /* Input mixers */ - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_vaiott_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc883_bind_cap_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc883_bind_cap_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { - HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), - HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_mitac_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc883_mitac_verbs[] = { - /* HP */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Subwoofer */ - {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* enable unsolicited event */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, */ - - { } /* end */ -}; - -static const struct hda_verb alc883_clevo_m540r_verbs[] = { - /* HP */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Int speaker */ - /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/ - - /* enable unsolicited event */ - /* - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - */ - - { } /* end */ -}; - -static const struct hda_verb alc883_clevo_m720_verbs[] = { - /* HP */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Int speaker */ - {0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* enable unsolicited event */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - - { } /* end */ -}; - -static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { - /* HP */ - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Subwoofer */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* enable unsolicited event */ - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } /* end */ -}; - -static const struct hda_verb alc883_targa_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - -/* Connect Line-Out side jack (SPDIF) to Side */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, -/* Connect Mic jack to CLFE */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, -/* Connect Line-in jack to Surround */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, -/* Connect HP out jack to Front */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } /* end */ -}; - -static const struct hda_verb alc883_lenovo_101e_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_FRONT_EVENT|AC_USRSP_EN}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT|AC_USRSP_EN}, - { } /* end */ -}; - -static const struct hda_verb alc883_lenovo_nb0763_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - { } /* end */ -}; - -static const struct hda_verb alc888_lenovo_ms7195_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_FRONT_EVENT | AC_USRSP_EN}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -static const struct hda_verb alc883_haier_w66_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - { } /* end */ -}; - -static const struct hda_verb alc888_lenovo_sky_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -static const struct hda_verb alc888_6st_dell_verbs[] = { - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } -}; - -static const struct hda_verb alc883_vaiott_verbs[] = { - /* HP */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - - /* enable unsolicited event */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - - { } /* end */ -}; - -static void alc888_3st_hp_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x18; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc888_3st_hp_verbs[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ - {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */ - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc888_3st_hp_2ch_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static const struct hda_verb alc888_3st_hp_4ch_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc888_3st_hp_6ch_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc888_3st_hp_modes[3] = { - { 2, alc888_3st_hp_2ch_init }, - { 4, alc888_3st_hp_4ch_init }, - { 6, alc888_3st_hp_6ch_init }, -}; - -static void alc888_lenovo_ms7195_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.line_out_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_lenovo_nb0763_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* toggle speaker-output according to the hp-jack state */ -#define alc883_targa_init_hook alc882_targa_init_hook -#define alc883_targa_unsol_event alc882_targa_unsol_event - -static void alc883_clevo_m720_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc883_clevo_m720_init_hook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc88x_simple_mic_automute(codec); -} - -static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC_MIC_EVENT: - alc88x_simple_mic_automute(codec); - break; - default: - alc_sku_unsol_event(codec, res); - break; - } -} - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc883_haier_w66_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc883_lenovo_101e_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.line_out_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->detect_line = 1; - spec->automute_lines = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_acer_aspire_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->autocfg.speaker_pins[1] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc883_acer_eapd_verbs[] = { - /* HP Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Front Pin: output 0 (0x0c) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* eanable EAPD on medion laptop */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, - /* enable unsolicited event */ - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } -}; - -static void alc888_6st_dell_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - spec->autocfg.speaker_pins[3] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc888_lenovo_sky_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - spec->autocfg.speaker_pins[3] = 0x17; - spec->autocfg.speaker_pins[4] = 0x1a; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc883_vaiott_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc888_asus_m90v_verbs[] = { - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* enable unsolicited event */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -static void alc883_mode2_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static const struct hda_verb alc888_asus_eee1601_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0838}, - /* enable unsolicited event */ - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -static void alc883_eee1601_inithook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - alc_hp_automute(codec); -} - -static const struct hda_verb alc889A_mb31_verbs[] = { - /* Init rear pin (used as headphone output) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Init line pin (used as output in 4ch and 6ch mode) */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */ - /* Init line 2 pin (used as headphone out by default) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */ - { } /* end */ -}; - -/* Mute speakers according to the headphone jack state */ -static void alc889A_mb31_automute(struct hda_codec *codec) -{ - unsigned int present; - - /* Mute only in 2ch or 4ch mode */ - if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0) - == 0x00) { - present = snd_hda_jack_detect(codec, 0x15); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - } -} - -static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc889A_mb31_automute(codec); -} - -static const hda_nid_t alc883_slave_dig_outs[] = { - ALC1200_DIGOUT_NID, 0, -}; - -static const hda_nid_t alc1200_slave_dig_outs[] = { - ALC883_DIGOUT_NID, 0, -}; - -/* - * configuration and preset - */ -static const char * const alc882_models[ALC882_MODEL_LAST] = { - [ALC882_3ST_DIG] = "3stack-dig", - [ALC882_6ST_DIG] = "6stack-dig", - [ALC882_ARIMA] = "arima", - [ALC882_W2JC] = "w2jc", - [ALC882_TARGA] = "targa", - [ALC882_ASUS_A7J] = "asus-a7j", - [ALC882_ASUS_A7M] = "asus-a7m", - [ALC885_MACPRO] = "macpro", - [ALC885_MB5] = "mb5", - [ALC885_MACMINI3] = "macmini3", - [ALC885_MBA21] = "mba21", - [ALC885_MBP3] = "mbp3", - [ALC885_IMAC24] = "imac24", - [ALC885_IMAC91] = "imac91", - [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig", - [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig", - [ALC883_3ST_6ch] = "3stack-6ch", - [ALC883_6ST_DIG] = "alc883-6stack-dig", - [ALC883_TARGA_DIG] = "targa-dig", - [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", - [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig", - [ALC883_ACER] = "acer", - [ALC883_ACER_ASPIRE] = "acer-aspire", - [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", - [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g", - [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g", - [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g", - [ALC883_MEDION] = "medion", - [ALC883_MEDION_WIM2160] = "medion-wim2160", - [ALC883_LAPTOP_EAPD] = "laptop-eapd", - [ALC883_LENOVO_101E_2ch] = "lenovo-101e", - [ALC883_LENOVO_NB0763] = "lenovo-nb0763", - [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig", - [ALC888_LENOVO_SKY] = "lenovo-sky", - [ALC883_HAIER_W66] = "haier-w66", - [ALC888_3ST_HP] = "3stack-hp", - [ALC888_6ST_DELL] = "6stack-dell", - [ALC883_MITAC] = "mitac", - [ALC883_CLEVO_M540R] = "clevo-m540r", - [ALC883_CLEVO_M720] = "clevo-m720", - [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", - [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", - [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", - [ALC889A_INTEL] = "intel-alc889a", - [ALC889_INTEL] = "intel-x58", - [ALC1200_ASUS_P5Q] = "asus-p5q", - [ALC889A_MB31] = "mb31", - [ALC883_SONY_VAIO_TT] = "sony-vaio-tt", - [ALC882_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc882_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), - - SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", - ALC888_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", - ALC888_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", - ALC888_ACER_ASPIRE_8930G), - SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", - ALC888_ACER_ASPIRE_8930G), - SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO), - SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO), - SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", - ALC888_ACER_ASPIRE_6530G), - SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", - ALC888_ACER_ASPIRE_6530G), - SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", - ALC888_ACER_ASPIRE_7730G), - /* default Acer -- disabled as it causes more problems. - * model=auto should work fine now - */ - /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */ - - SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), - - SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), - SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), - SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP), - SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP), - - SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), - SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), - SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), - SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), - SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), - SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q), - SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), - - SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT), - SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC), - SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC), - SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), - SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL), - SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), - - SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ - SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO), - SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG), - SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG), - - SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), - SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720), - SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R), - SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD), - SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), - /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */ - SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), - SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx", - ALC883_FUJITSU_PI2515), - SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx", - ALC888_FUJITSU_XA3530), - SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), - SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), - SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), - SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), - SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY), - SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG), - SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), - - SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), - SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL), - SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC), - SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL), - SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL), - SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL), - SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG), - - {} -}; - -/* codec SSID table for Intel Mac */ -static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { - SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO), - SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), - SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), - SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), - SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M), - SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21), - SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), - SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), - SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91), - SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), - SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5), - /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, - * so apparently no perfect solution yet - */ - SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), - SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), - SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3), - {} /* terminator */ -}; - -static const struct alc_config_preset alc882_presets[] = { - [ALC882_3ST_DIG] = { - .mixers = { alc882_base_mixer }, - .init_verbs = { alc882_base_init_verbs, - alc882_adc1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - }, - [ALC882_6ST_DIG] = { - .mixers = { alc882_base_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, - alc882_adc1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), - .channel_mode = alc882_sixstack_modes, - .input_mux = &alc882_capture_source, - }, - [ALC882_ARIMA] = { - .mixers = { alc882_base_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc882_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), - .channel_mode = alc882_sixstack_modes, - .input_mux = &alc882_capture_source, - }, - [ALC882_W2JC] = { - .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc882_eapd_verbs, alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - }, - [ALC885_MBA21] = { - .mixers = { alc885_mba21_mixer }, - .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs }, - .num_dacs = 2, - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mba21_ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), - .input_mux = &alc882_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_mba21_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MBP3] = { - .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_mbp3_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = 2, - .dac_nids = alc882_dac_nids, - .hp_nid = 0x04, - .channel_mode = alc885_mbp_4ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes), - .input_mux = &alc882_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_mbp3_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MB5] = { - .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_mb5_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mb5_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), - .input_mux = &mb5_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_mb5_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MACMINI3] = { - .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_macmini3_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_macmini3_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes), - .input_mux = &macmini3_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_macmini3_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MACPRO] = { - .mixers = { alc882_macpro_mixer }, - .init_verbs = { alc882_macpro_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .input_mux = &alc882_capture_source, - .init_hook = alc885_macpro_init_hook, - }, - [ALC885_IMAC24] = { - .mixers = { alc885_imac24_mixer }, - .init_verbs = { alc885_imac24_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .input_mux = &alc882_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_imac24_setup, - .init_hook = alc885_imac24_init_hook, - }, - [ALC885_IMAC91] = { - .mixers = {alc885_imac91_mixer}, - .init_verbs = { alc885_imac91_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mba21_ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), - .input_mux = &alc889A_imac91_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc885_imac91_setup, - .init_hook = alc_hp_automute, - }, - [ALC882_TARGA] = { - .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc880_gpio3_init_verbs, alc882_targa_verbs}, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), - .adc_nids = alc882_adc_nids, - .capsrc_nids = alc882_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), - .channel_mode = alc882_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, - }, - [ALC882_ASUS_A7J] = { - .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc882_asus_a7j_verbs}, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), - .adc_nids = alc882_adc_nids, - .capsrc_nids = alc882_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), - .channel_mode = alc882_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - }, - [ALC882_ASUS_A7M] = { - .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc882_eapd_verbs, alc880_gpio1_init_verbs, - alc882_asus_a7m_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - }, - [ALC883_3ST_2ch_DIG] = { - .mixers = { alc883_3ST_2ch_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_3ST_6ch_DIG] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - }, - [ALC883_3ST_6ch] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - }, - [ALC883_3ST_6ch_INTEL] = { - .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .slave_dig_outs = alc883_slave_dig_outs, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes), - .channel_mode = alc883_3ST_6ch_intel_modes, - .need_dac_fix = 1, - .input_mux = &alc883_3stack_6ch_intel, - }, - [ALC889A_INTEL] = { - .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, - .init_verbs = { alc885_init_verbs, alc885_init_input_verbs, - alc_hp15_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), - .adc_nids = alc889_adc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .slave_dig_outs = alc883_slave_dig_outs, - .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes), - .channel_mode = alc889_8ch_intel_modes, - .capsrc_nids = alc889_capsrc_nids, - .input_mux = &alc889_capture_source, - .setup = alc889_automute_setup, - .init_hook = alc_hp_automute, - .unsol_event = alc_sku_unsol_event, - .need_dac_fix = 1, - }, - [ALC889_INTEL] = { - .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, - .init_verbs = { alc885_init_verbs, alc889_init_input_verbs, - alc889_eapd_verbs, alc_hp15_unsol_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), - .adc_nids = alc889_adc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .slave_dig_outs = alc883_slave_dig_outs, - .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes), - .channel_mode = alc889_8ch_intel_modes, - .capsrc_nids = alc889_capsrc_nids, - .input_mux = &alc889_capture_source, - .setup = alc889_automute_setup, - .init_hook = alc889_intel_init_hook, - .unsol_event = alc_sku_unsol_event, - .need_dac_fix = 1, - }, - [ALC883_6ST_DIG] = { - .mixers = { alc883_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_TARGA_DIG] = { - .mixers = { alc883_targa_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, - alc883_targa_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_targa_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, - }, - [ALC883_TARGA_2ch_DIG] = { - .mixers = { alc883_targa_2ch_mixer}, - .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, - alc883_targa_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), - .capsrc_nids = alc883_capsrc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_targa_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, - }, - [ALC883_TARGA_8ch_DIG] = { - .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, - alc883_targa_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes), - .channel_mode = alc883_4ST_8ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_targa_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, - }, - [ALC883_ACER] = { - .mixers = { alc883_base_mixer }, - /* On TravelMate laptops, GPIO 0 enables the internal speaker - * and the headphone jack. Turn this on and rely on the - * standard mute methods whenever the user wants to turn - * these outputs off. - */ - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_ACER_ASPIRE] = { - .mixers = { alc883_acer_aspire_mixer }, - .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_acer_aspire_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_ACER_ASPIRE_4930G] = { - .mixers = { alc888_acer_aspire_4930g_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc888_acer_aspire_4930g_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .const_channel_count = 6, - .num_mux_defs = - ARRAY_SIZE(alc888_2_capture_sources), - .input_mux = alc888_2_capture_sources, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_acer_aspire_4930g_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_ACER_ASPIRE_6530G] = { - .mixers = { alc888_acer_aspire_6530_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc888_acer_aspire_6530g_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .num_mux_defs = - ARRAY_SIZE(alc888_2_capture_sources), - .input_mux = alc888_acer_aspire_6530_sources, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_acer_aspire_6530g_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_ACER_ASPIRE_8930G] = { - .mixers = { alc889_acer_aspire_8930g_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc889_acer_aspire_8930g_verbs, - alc889_eapd_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), - .adc_nids = alc889_adc_nids, - .capsrc_nids = alc889_capsrc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .const_channel_count = 6, - .num_mux_defs = - ARRAY_SIZE(alc889_capture_sources), - .input_mux = alc889_capture_sources, - .unsol_event = alc_sku_unsol_event, - .setup = alc889_acer_aspire_8930g_setup, - .init_hook = alc_hp_automute, -#ifdef CONFIG_SND_HDA_POWER_SAVE - .power_hook = alc_power_eapd, -#endif - }, - [ALC888_ACER_ASPIRE_7730G] = { - .mixers = { alc883_3ST_6ch_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc888_acer_aspire_7730G_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .const_channel_count = 6, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_acer_aspire_7730g_setup, - .init_hook = alc_hp_automute, - }, - [ALC883_MEDION] = { - .mixers = { alc883_fivestack_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, - alc883_medion_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), - .capsrc_nids = alc883_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_MEDION_WIM2160] = { - .mixers = { alc883_medion_wim2160_mixer }, - .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_medion_wim2160_setup, - .init_hook = alc_hp_automute, - }, - [ALC883_LAPTOP_EAPD] = { - .mixers = { alc883_base_mixer }, - .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_CLEVO_M540R] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes), - .channel_mode = alc883_3ST_6ch_clevo_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - /* This machine has the hardware HP auto-muting, thus - * we need no software mute via unsol event - */ - }, - [ALC883_CLEVO_M720] = { - .mixers = { alc883_clevo_m720_mixer }, - .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_clevo_m720_unsol_event, - .setup = alc883_clevo_m720_setup, - .init_hook = alc883_clevo_m720_init_hook, - }, - [ALC883_LENOVO_101E_2ch] = { - .mixers = { alc883_lenovo_101e_2ch_mixer}, - .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), - .capsrc_nids = alc883_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_lenovo_101e_capture_source, - .setup = alc883_lenovo_101e_setup, - .unsol_event = alc_sku_unsol_event, - .init_hook = alc_inithook, - }, - [ALC883_LENOVO_NB0763] = { - .mixers = { alc883_lenovo_nb0763_mixer }, - .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_lenovo_nb0763_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_lenovo_nb0763_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_LENOVO_MS7195_DIG] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_lenovo_ms7195_setup, - .init_hook = alc_inithook, - }, - [ALC883_HAIER_W66] = { - .mixers = { alc883_targa_2ch_mixer}, - .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_haier_w66_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_3ST_HP] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes), - .channel_mode = alc888_3st_hp_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_3st_hp_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_6ST_DELL] = { - .mixers = { alc883_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_6st_dell_setup, - .init_hook = alc_hp_automute, - }, - [ALC883_MITAC] = { - .mixers = { alc883_mitac_mixer }, - .init_verbs = { alc883_init_verbs, alc883_mitac_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_mitac_setup, - .init_hook = alc_hp_automute, - }, - [ALC883_FUJITSU_PI2515] = { - .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, - .init_verbs = { alc883_init_verbs, - alc883_2ch_fujitsu_pi2515_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_2ch_fujitsu_pi2515_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_FUJITSU_XA3530] = { - .mixers = { alc888_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, - alc888_fujitsu_xa3530_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes), - .channel_mode = alc888_4ST_8ch_intel_modes, - .num_mux_defs = - ARRAY_SIZE(alc888_2_capture_sources), - .input_mux = alc888_2_capture_sources, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_fujitsu_xa3530_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_LENOVO_SKY] = { - .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .need_dac_fix = 1, - .input_mux = &alc883_lenovo_sky_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc888_lenovo_sky_setup, - .init_hook = alc_hp_automute, - }, - [ALC888_ASUS_M90V] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_mode2_setup, - .init_hook = alc_inithook, - }, - [ALC888_ASUS_EEE1601] = { - .mixers = { alc883_asus_eee1601_mixer }, - .cap_mixer = alc883_asus_eee1601_cap_mixer, - .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_asus_eee1601_capture_source, - .unsol_event = alc_sku_unsol_event, - .init_hook = alc883_eee1601_inithook, - }, - [ALC1200_ASUS_P5Q] = { - .mixers = { alc883_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC1200_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .slave_dig_outs = alc1200_slave_dig_outs, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - }, - [ALC889A_MB31] = { - .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer}, - .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs, - alc880_gpio1_init_verbs }, - .adc_nids = alc883_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .capsrc_nids = alc883_capsrc_nids, - .dac_nids = alc883_dac_nids, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .channel_mode = alc889A_mb31_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes), - .input_mux = &alc889A_mb31_capture_source, - .dig_out_nid = ALC883_DIGOUT_NID, - .unsol_event = alc889A_mb31_unsol_event, - .init_hook = alc889A_mb31_automute, - }, - [ALC883_SONY_VAIO_TT] = { - .mixers = { alc883_vaiott_mixer }, - .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_vaiott_setup, - .init_hook = alc_hp_automute, - }, -}; - - diff --git a/trunk/sound/pci/hda/alc_quirks.c b/trunk/sound/pci/hda/alc_quirks.c deleted file mode 100644 index 2be1129cf458..000000000000 --- a/trunk/sound/pci/hda/alc_quirks.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Common codes for Realtek codec quirks - * included by patch_realtek.c - */ - -/* - * configuration template - to be copied to the spec instance - */ -struct alc_config_preset { - const struct snd_kcontrol_new *mixers[5]; /* should be identical size - * with spec - */ - const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ - const struct hda_verb *init_verbs[5]; - unsigned int num_dacs; - const hda_nid_t *dac_nids; - hda_nid_t dig_out_nid; /* optional */ - hda_nid_t hp_nid; /* optional */ - const hda_nid_t *slave_dig_outs; - unsigned int num_adc_nids; - const hda_nid_t *adc_nids; - const hda_nid_t *capsrc_nids; - hda_nid_t dig_in_nid; - unsigned int num_channel_mode; - const struct hda_channel_mode *channel_mode; - int need_dac_fix; - int const_channel_count; - unsigned int num_mux_defs; - const struct hda_input_mux *input_mux; - void (*unsol_event)(struct hda_codec *, unsigned int); - void (*setup)(struct hda_codec *); - void (*init_hook)(struct hda_codec *); -#ifdef CONFIG_SND_HDA_POWER_SAVE - const struct hda_amp_list *loopbacks; - void (*power_hook)(struct hda_codec *codec); -#endif -}; - -/* - * channel mode setting - */ -static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - spec->ext_channel_count); -} - -static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->ext_channel_count); - if (err >= 0 && !spec->const_channel_count) { - spec->multiout.max_channels = spec->ext_channel_count; - if (spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - } - return err; -} - -/* - * Control the mode of pin widget settings via the mixer. "pc" is used - * instead of "%" to avoid consequences of accidentally treating the % as - * being part of a format specifier. Maximum allowed length of a value is - * 63 characters plus NULL terminator. - * - * Note: some retasking pin complexes seem to ignore requests for input - * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these - * are requested. Therefore order this list so that this behaviour will not - * cause problems when mixer clients move through the enum sequentially. - * NIDs 0x0f and 0x10 have been observed to have this behaviour as of - * March 2006. - */ -static const char * const alc_pin_mode_names[] = { - "Mic 50pc bias", "Mic 80pc bias", - "Line in", "Line out", "Headphone out", -}; -static const unsigned char alc_pin_mode_values[] = { - PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP, -}; -/* The control can present all 5 options, or it can limit the options based - * in the pin being assumed to be exclusively an input or an output pin. In - * addition, "input" pins may or may not process the mic bias option - * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to - * accept requests for bias as of chip versions up to March 2006) and/or - * wiring in the computer. - */ -#define ALC_PIN_DIR_IN 0x00 -#define ALC_PIN_DIR_OUT 0x01 -#define ALC_PIN_DIR_INOUT 0x02 -#define ALC_PIN_DIR_IN_NOMICBIAS 0x03 -#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04 - -/* Info about the pin modes supported by the different pin direction modes. - * For each direction the minimum and maximum values are given. - */ -static const signed char alc_pin_mode_dir_info[5][2] = { - { 0, 2 }, /* ALC_PIN_DIR_IN */ - { 3, 4 }, /* ALC_PIN_DIR_OUT */ - { 0, 4 }, /* ALC_PIN_DIR_INOUT */ - { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */ - { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */ -}; -#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0]) -#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1]) -#define alc_pin_mode_n_items(_dir) \ - (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1) - -static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - unsigned int item_num = uinfo->value.enumerated.item; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = alc_pin_mode_n_items(dir); - - if (item_numalc_pin_mode_max(dir)) - item_num = alc_pin_mode_min(dir); - strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]); - return 0; -} - -static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int i; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - - /* Find enumerated value for current pinctl setting */ - i = alc_pin_mode_min(dir); - while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl) - i++; - *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir); - return 0; -} - -static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - - if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir)) - val = alc_pin_mode_min(dir); - - change = pinctl != alc_pin_mode_values[val]; - if (change) { - /* Set pin mode to that requested */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - alc_pin_mode_values[val]); - - /* Also enable the retasking pin's input/output as required - * for the requested pin mode. Enum values of 2 or less are - * input modes. - * - * Dynamically switching the input/output buffers probably - * reduces noise slightly (particularly on input) so we'll - * do it. However, having both input and output buffers - * enabled simultaneously doesn't seem to be problematic if - * this turns out to be necessary in the future. - */ - if (val <= 2) { - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, - HDA_AMP_MUTE, 0); - } else { - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, 0); - } - } - return change; -} - -#define ALC_PIN_MODE(xname, nid, dir) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_pin_mode_info, \ - .get = alc_pin_mode_get, \ - .put = alc_pin_mode_put, \ - .private_value = nid | (dir<<16) } - -/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged - * together using a mask with more than one bit set. This control is - * currently used only by the ALC260 test model. At this stage they are not - * needed for any "production" models. - */ -#ifdef CONFIG_SND_DEBUG -#define alc_gpio_data_info snd_ctl_boolean_mono_info - -static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_GPIO_DATA, 0x00); - - *valp = (val & mask) != 0; - return 0; -} -static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_GPIO_DATA, - 0x00); - - /* Set/unset the masked GPIO bit(s) as needed */ - change = (val == 0 ? 0 : mask) != (gpio_data & mask); - if (val == 0) - gpio_data &= ~mask; - else - gpio_data |= mask; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_GPIO_DATA, gpio_data); - - return change; -} -#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_gpio_data_info, \ - .get = alc_gpio_data_get, \ - .put = alc_gpio_data_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -/* A switch control to allow the enabling of the digital IO pins on the - * ALC260. This is incredibly simplistic; the intention of this control is - * to provide something in the test model allowing digital outputs to be - * identified if present. If models are found which can utilise these - * outputs a more complete mixer control can be devised for those models if - * necessary. - */ -#ifdef CONFIG_SND_DEBUG -#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info - -static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_DIGI_CONVERT_1, 0x00); - - *valp = (val & mask) != 0; - return 0; -} -static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_DIGI_CONVERT_1, - 0x00); - - /* Set/unset the masked control bit(s) as needed */ - change = (val == 0 ? 0 : mask) != (ctrl_data & mask); - if (val==0) - ctrl_data &= ~mask; - else - ctrl_data |= mask; - snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - ctrl_data); - - return change; -} -#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_spdif_ctrl_info, \ - .get = alc_spdif_ctrl_get, \ - .put = alc_spdif_ctrl_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -/* A switch control to allow the enabling EAPD digital outputs on the ALC26x. - * Again, this is only used in the ALC26x test models to help identify when - * the EAPD line must be asserted for features to work. - */ -#ifdef CONFIG_SND_DEBUG -#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info - -static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_EAPD_BTLENABLE, 0x00); - - *valp = (val & mask) != 0; - return 0; -} - -static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_EAPD_BTLENABLE, - 0x00); - - /* Set/unset the masked control bit(s) as needed */ - change = (!val ? 0 : mask) != (ctrl_data & mask); - if (!val) - ctrl_data &= ~mask; - else - ctrl_data |= mask; - snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, - ctrl_data); - - return change; -} - -#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_eapd_ctrl_info, \ - .get = alc_eapd_ctrl_get, \ - .put = alc_eapd_ctrl_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - if (!cfg->line_outs) { - while (cfg->line_outs < AUTO_CFG_MAX_OUTS && - cfg->line_out_pins[cfg->line_outs]) - cfg->line_outs++; - } - if (!cfg->speaker_outs) { - while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS && - cfg->speaker_pins[cfg->speaker_outs]) - cfg->speaker_outs++; - } - if (!cfg->hp_outs) { - while (cfg->hp_outs < AUTO_CFG_MAX_OUTS && - cfg->hp_pins[cfg->hp_outs]) - cfg->hp_outs++; - } -} - -/* - * set up from the preset table - */ -static void setup_preset(struct hda_codec *codec, - const struct alc_config_preset *preset) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) - add_mixer(spec, preset->mixers[i]); - spec->cap_mixer = preset->cap_mixer; - for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; - i++) - add_verb(spec, preset->init_verbs[i]); - - spec->channel_mode = preset->channel_mode; - spec->num_channel_mode = preset->num_channel_mode; - spec->need_dac_fix = preset->need_dac_fix; - spec->const_channel_count = preset->const_channel_count; - - if (preset->const_channel_count) - spec->multiout.max_channels = preset->const_channel_count; - else - spec->multiout.max_channels = spec->channel_mode[0].channels; - spec->ext_channel_count = spec->channel_mode[0].channels; - - spec->multiout.num_dacs = preset->num_dacs; - spec->multiout.dac_nids = preset->dac_nids; - spec->multiout.dig_out_nid = preset->dig_out_nid; - spec->multiout.slave_dig_outs = preset->slave_dig_outs; - spec->multiout.hp_nid = preset->hp_nid; - - spec->num_mux_defs = preset->num_mux_defs; - if (!spec->num_mux_defs) - spec->num_mux_defs = 1; - spec->input_mux = preset->input_mux; - - spec->num_adc_nids = preset->num_adc_nids; - spec->adc_nids = preset->adc_nids; - spec->capsrc_nids = preset->capsrc_nids; - spec->dig_in_nid = preset->dig_in_nid; - - spec->unsol_event = preset->unsol_event; - spec->init_hook = preset->init_hook; -#ifdef CONFIG_SND_HDA_POWER_SAVE - spec->power_hook = preset->power_hook; - spec->loopback.amplist = preset->loopbacks; -#endif - - if (preset->setup) - preset->setup(codec); - - alc_fixup_autocfg_pin_nums(codec); -} - - -/* auto-toggle front mic */ -static void alc88x_simple_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x18); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); -} - diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index 9c27a3a4c4d5..45b4a8d70e08 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -243,8 +243,7 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, { unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm); unsigned int res; - if (codec_exec_verb(codec, cmd, &res)) - return -1; + codec_exec_verb(codec, cmd, &res); return res; } EXPORT_SYMBOL_HDA(snd_hda_codec_read); @@ -308,107 +307,63 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); -/* look up the cached results */ -static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid) -{ - int i, len; - for (i = 0; i < array->used; ) { - hda_nid_t *p = snd_array_elem(array, i); - if (nid == *p) - return p; - len = p[1]; - i += len + 2; - } - return NULL; -} +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns); +static bool add_conn_list(struct snd_array *array, hda_nid_t nid); +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst, + hda_nid_t *src, int len); /** - * snd_hda_get_conn_list - get connection list + * snd_hda_get_connections - get connection list * @codec: the HDA codec * @nid: NID to parse - * @listp: the pointer to store NID list + * @conn_list: connection list array + * @max_conns: max. number of connections to store * * Parses the connection list of the given widget and stores the list * of NIDs. * * Returns the number of connections, or a negative error code. */ -int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, - const hda_nid_t **listp) +int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns) { struct snd_array *array = &codec->conn_lists; - int len, err; + int i, len, old_used; hda_nid_t list[HDA_MAX_CONNECTIONS]; - hda_nid_t *p; - bool added = false; - again: - /* if the connection-list is already cached, read it */ - p = lookup_conn_list(array, nid); - if (p) { - if (listp) - *listp = p + 2; - return p[1]; + /* look up the cached results */ + for (i = 0; i < array->used; ) { + hda_nid_t *p = snd_array_elem(array, i); + len = p[1]; + if (nid == *p) + return copy_conn_list(nid, conn_list, max_conns, + p + 2, len); + i += len + 2; } - if (snd_BUG_ON(added)) - return -EINVAL; - /* read the connection and add to the cache */ - len = snd_hda_get_raw_connections(codec, nid, list, HDA_MAX_CONNECTIONS); + len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS); if (len < 0) return len; - err = snd_hda_override_conn_list(codec, nid, len, list); - if (err < 0) - return err; - added = true; - goto again; -} -EXPORT_SYMBOL_HDA(snd_hda_get_conn_list); -/** - * snd_hda_get_connections - copy connection list - * @codec: the HDA codec - * @nid: NID to parse - * @conn_list: connection list array - * @max_conns: max. number of connections to store - * - * Parses the connection list of the given widget and stores the list - * of NIDs. - * - * Returns the number of connections, or a negative error code. - */ -int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *conn_list, int max_conns) -{ - const hda_nid_t *list; - int len = snd_hda_get_conn_list(codec, nid, &list); + /* add to the cache */ + old_used = array->used; + if (!add_conn_list(array, nid) || !add_conn_list(array, len)) + goto error_add; + for (i = 0; i < len; i++) + if (!add_conn_list(array, list[i])) + goto error_add; - if (len <= 0) - return len; - if (len > max_conns) { - snd_printk(KERN_ERR "hda_codec: " - "Too many connections %d for NID 0x%x\n", - len, nid); - return -EINVAL; - } - memcpy(conn_list, list, len * sizeof(hda_nid_t)); - return len; + return copy_conn_list(nid, conn_list, max_conns, list, len); + + error_add: + array->used = old_used; + return -ENOMEM; } EXPORT_SYMBOL_HDA(snd_hda_get_connections); -/** - * snd_hda_get_raw_connections - copy connection list without cache - * @codec: the HDA codec - * @nid: NID to parse - * @conn_list: connection list array - * @max_conns: max. number of connections to store - * - * Like snd_hda_get_connections(), copy the connection list but without - * checking through the connection-list cache. - * Currently called only from hda_proc.c, so not exported. - */ -int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *conn_list, int max_conns) +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns) { unsigned int parm; int i, conn_len, conns; @@ -421,8 +376,11 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, wcaps = get_wcaps(codec, nid); if (!(wcaps & AC_WCAP_CONN_LIST) && - get_wcaps_type(wcaps) != AC_WID_VOL_KNB) - return 0; + get_wcaps_type(wcaps) != AC_WID_VOL_KNB) { + snd_printk(KERN_WARNING "hda_codec: " + "connection list not available for 0x%x\n", nid); + return -EINVAL; + } parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN); if (parm & AC_CLIST_LONG) { @@ -512,77 +470,18 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid) return true; } -/** - * snd_hda_override_conn_list - add/modify the connection-list to cache - * @codec: the HDA codec - * @nid: NID to parse - * @len: number of connection list entries - * @list: the list of connection entries - * - * Add or modify the given connection-list to the cache. If the corresponding - * cache already exists, invalidate it and append a new one. - * - * Returns zero or a negative error code. - */ -int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, - const hda_nid_t *list) +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst, + hda_nid_t *src, int len) { - struct snd_array *array = &codec->conn_lists; - hda_nid_t *p; - int i, old_used; - - p = lookup_conn_list(array, nid); - if (p) - *p = -1; /* invalidate the old entry */ - - old_used = array->used; - if (!add_conn_list(array, nid) || !add_conn_list(array, len)) - goto error_add; - for (i = 0; i < len; i++) - if (!add_conn_list(array, list[i])) - goto error_add; - return 0; - - error_add: - array->used = old_used; - return -ENOMEM; -} -EXPORT_SYMBOL_HDA(snd_hda_override_conn_list); - -/** - * snd_hda_get_conn_index - get the connection index of the given NID - * @codec: the HDA codec - * @mux: NID containing the list - * @nid: NID to select - * @recursive: 1 when searching NID recursively, otherwise 0 - * - * Parses the connection list of the widget @mux and checks whether the - * widget @nid is present. If it is, return the connection index. - * Otherwise it returns -1. - */ -int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t nid, int recursive) -{ - hda_nid_t conn[HDA_MAX_NUM_INPUTS]; - int i, nums; - - nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); - for (i = 0; i < nums; i++) - if (conn[i] == nid) - return i; - if (!recursive) - return -1; - if (recursive > 5) { - snd_printd("hda_codec: too deep connection for 0x%x\n", nid); - return -1; + if (len > max_dst) { + snd_printk(KERN_ERR "hda_codec: " + "Too many connections %d for NID 0x%x\n", + len, nid); + return -EINVAL; } - recursive++; - for (i = 0; i < nums; i++) - if (snd_hda_get_conn_index(codec, conn[i], nid, recursive) >= 0) - return i; - return -1; + memcpy(dst, src, len * sizeof(hda_nid_t)); + return len; } -EXPORT_SYMBOL_HDA(snd_hda_get_conn_index); /** * snd_hda_queue_unsol_event - add an unsolicited event to queue @@ -1184,7 +1083,6 @@ static void snd_hda_codec_free(struct hda_codec *codec) snd_array_free(&codec->mixers); snd_array_free(&codec->nids); snd_array_free(&codec->conn_lists); - snd_array_free(&codec->spdif_out); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); @@ -1246,7 +1144,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64); - snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { @@ -2658,13 +2555,11 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->private_value; - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - ucontrol->value.iec958.status[0] = spdif->status & 0xff; - ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff; - ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff; - ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff; + ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff; + ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff; return 0; } @@ -2749,23 +2644,23 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->private_value; - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - hda_nid_t nid = spdif->nid; + hda_nid_t nid = kcontrol->private_value; unsigned short val; int change; mutex_lock(&codec->spdif_mutex); - spdif->status = ucontrol->value.iec958.status[0] | + codec->spdif_status = ucontrol->value.iec958.status[0] | ((unsigned int)ucontrol->value.iec958.status[1] << 8) | ((unsigned int)ucontrol->value.iec958.status[2] << 16) | ((unsigned int)ucontrol->value.iec958.status[3] << 24); - val = convert_from_spdif_status(spdif->status); - val |= spdif->ctls & 1; - change = spdif->ctls != val; - spdif->ctls = val; - if (change && nid != (u16)-1) + val = convert_from_spdif_status(codec->spdif_status); + val |= codec->spdif_ctls & 1; + change = codec->spdif_ctls != val; + codec->spdif_ctls = val; + + if (change) set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff); + mutex_unlock(&codec->spdif_mutex); return change; } @@ -2776,42 +2671,33 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->private_value; - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE; + ucontrol->value.integer.value[0] = codec->spdif_ctls & AC_DIG1_ENABLE; return 0; } -static inline void set_spdif_ctls(struct hda_codec *codec, hda_nid_t nid, - int dig1, int dig2) -{ - set_dig_out_convert(codec, nid, dig1, dig2); - /* unmute amp switch (if any) */ - if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && - (dig1 & AC_DIG1_ENABLE)) - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, 0); -} - static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->private_value; - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - hda_nid_t nid = spdif->nid; + hda_nid_t nid = kcontrol->private_value; unsigned short val; int change; mutex_lock(&codec->spdif_mutex); - val = spdif->ctls & ~AC_DIG1_ENABLE; + val = codec->spdif_ctls & ~AC_DIG1_ENABLE; if (ucontrol->value.integer.value[0]) val |= AC_DIG1_ENABLE; - change = spdif->ctls != val; - spdif->ctls = val; - if (change && nid != (u16)-1) - set_spdif_ctls(codec, nid, val & 0xff, -1); + change = codec->spdif_ctls != val; + if (change) { + codec->spdif_ctls = val; + set_dig_out_convert(codec, nid, val & 0xff, -1); + /* unmute amp switch (if any) */ + if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && + (val & AC_DIG1_ENABLE)) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); + } mutex_unlock(&codec->spdif_mutex); return change; } @@ -2858,79 +2744,36 @@ static struct snd_kcontrol_new dig_mixes[] = { * * Returns 0 if successful, or a negative error code. */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t associated_nid, - hda_nid_t cvt_nid) +int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) { int err; struct snd_kcontrol *kctl; struct snd_kcontrol_new *dig_mix; int idx; - struct hda_spdif_out *spdif; idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch"); if (idx < 0) { printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); return -EBUSY; } - spdif = snd_array_new(&codec->spdif_out); for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); if (!kctl) return -ENOMEM; kctl->id.index = idx; - kctl->private_value = codec->spdif_out.used - 1; - err = snd_hda_ctl_add(codec, associated_nid, kctl); + kctl->private_value = nid; + err = snd_hda_ctl_add(codec, nid, kctl); if (err < 0) return err; } - spdif->nid = cvt_nid; - spdif->ctls = snd_hda_codec_read(codec, cvt_nid, 0, - AC_VERB_GET_DIGI_CONVERT_1, 0); - spdif->status = convert_to_spdif_status(spdif->ctls); + codec->spdif_ctls = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT_1, 0); + codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); return 0; } EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); -struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, - hda_nid_t nid) -{ - int i; - for (i = 0; i < codec->spdif_out.used; i++) { - struct hda_spdif_out *spdif = - snd_array_elem(&codec->spdif_out, i); - if (spdif->nid == nid) - return spdif; - } - return NULL; -} -EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid); - -void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx) -{ - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - - mutex_lock(&codec->spdif_mutex); - spdif->nid = (u16)-1; - mutex_unlock(&codec->spdif_mutex); -} -EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign); - -void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid) -{ - struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - unsigned short val; - - mutex_lock(&codec->spdif_mutex); - if (spdif->nid != nid) { - spdif->nid = nid; - val = spdif->ctls; - set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff); - } - mutex_unlock(&codec->spdif_mutex); -} -EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_assign); - /* * SPDIF sharing with analog output */ @@ -3513,7 +3356,7 @@ static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) * * Returns 0 if successful, otherwise a negative error code. */ -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, +static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, unsigned int *bpsp) { unsigned int i, val, wcaps; @@ -3605,7 +3448,6 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, return 0; } -EXPORT_SYMBOL_HDA(snd_hda_query_supported_pcm); /** * snd_hda_is_supported_format - Check the validity of the format @@ -4335,12 +4177,10 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, unsigned int stream_tag, unsigned int format) { - struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(codec, nid); - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) set_dig_out_convert(codec, nid, - spdif->ctls & ~AC_DIG1_ENABLE & 0xff, + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff, -1); snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); if (codec->slave_dig_outs) { @@ -4350,9 +4190,9 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, format); } /* turn on again (if needed) */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) set_dig_out_convert(codec, nid, - spdif->ctls & 0xff, -1); + codec->spdif_ctls & 0xff, -1); } static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) @@ -4508,8 +4348,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, { const hda_nid_t *nids = mout->dac_nids; int chs = substream->runtime->channels; - struct hda_spdif_out *spdif = - snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid); int i; mutex_lock(&codec->spdif_mutex); @@ -4518,7 +4356,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, if (chs == 2 && snd_hda_is_supported_format(codec, mout->dig_out_nid, format) && - !(spdif->status & IEC958_AES0_NONAUDIO)) { + !(codec->spdif_status & IEC958_AES0_NONAUDIO)) { mout->dig_out_used = HDA_DIG_ANALOG_DUP; setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format); @@ -4690,7 +4528,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, unsigned int wid_caps = get_wcaps(codec, nid); unsigned int wid_type = get_wcaps_type(wid_caps); unsigned int def_conf; - short assoc, loc, conn, dev; + short assoc, loc; /* read all default configuration for pin complex */ if (wid_type != AC_WID_PIN) @@ -4700,19 +4538,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, continue; def_conf = snd_hda_codec_get_pincfg(codec, nid); - conn = get_defcfg_connect(def_conf); - if (conn == AC_JACK_PORT_NONE) + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) continue; loc = get_defcfg_location(def_conf); - dev = get_defcfg_device(def_conf); - - /* workaround for buggy BIOS setups */ - if (dev == AC_JACK_LINE_OUT) { - if (conn == AC_JACK_PORT_FIXED) - dev = AC_JACK_SPEAKER; - } - - switch (dev) { + switch (get_defcfg_device(def_conf)) { case AC_JACK_LINE_OUT: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); @@ -5128,15 +4957,17 @@ void *snd_array_new(struct snd_array *array) { if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; - int size = (num + 1) * array->elem_size; - int oldsize = array->alloced * array->elem_size; void *nlist; if (snd_BUG_ON(num >= 4096)) return NULL; - nlist = krealloc(array->list, size, GFP_KERNEL); + nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); if (!nlist) return NULL; - memset(nlist + oldsize, 0, size - oldsize); + if (array->list) { + memcpy(nlist, array->list, + array->elem_size * array->alloced); + kfree(array->list); + } array->list = nlist; array->alloced = num; } diff --git a/trunk/sound/pci/hda/hda_codec.h b/trunk/sound/pci/hda/hda_codec.h index f465e07a4879..59c97306c1de 100644 --- a/trunk/sound/pci/hda/hda_codec.h +++ b/trunk/sound/pci/hda/hda_codec.h @@ -829,7 +829,8 @@ struct hda_codec { struct mutex spdif_mutex; struct mutex control_mutex; - struct snd_array spdif_out; + unsigned int spdif_status; /* IEC958 status bits */ + unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ struct snd_array init_pins; /* initial (BIOS) pin configurations */ @@ -903,16 +904,6 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id); int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); -int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *conn_list, int max_conns); -int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, - const hda_nid_t **listp); -int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums, - const hda_nid_t *list); -int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t nid, int recursive); -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, - u32 *ratesp, u64 *formatsp, unsigned int *bpsp); struct hda_verb { hda_nid_t nid; @@ -956,17 +947,6 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, hda_nid_t nid, unsigned int cfg); /* for hwdep */ void snd_hda_shutup_pins(struct hda_codec *codec); -/* SPDIF controls */ -struct hda_spdif_out { - hda_nid_t nid; /* Converter nid values relate to */ - unsigned int status; /* IEC958 status bits */ - unsigned short ctls; /* SPDIF control bits */ -}; -struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, - hda_nid_t nid); -void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx); -void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid); - /* * Mixer */ @@ -1017,15 +997,17 @@ int snd_hda_suspend(struct hda_bus *bus); int snd_hda_resume(struct hda_bus *bus); #endif +#ifdef CONFIG_SND_HDA_POWER_SAVE static inline int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid) { -#ifdef CONFIG_SND_HDA_POWER_SAVE if (codec->patch_ops.check_power_status) return codec->patch_ops.check_power_status(codec, nid); -#endif return 0; } +#else +#define hda_call_check_power_status(codec, nid) 0 +#endif /* * get widget information diff --git a/trunk/sound/pci/hda/hda_eld.c b/trunk/sound/pci/hda/hda_eld.c index 28ce17d09c33..e3e853153d14 100644 --- a/trunk/sound/pci/hda/hda_eld.c +++ b/trunk/sound/pci/hda/hda_eld.c @@ -580,45 +580,43 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) #endif /* CONFIG_PROC_FS */ /* update PCM info based on ELD */ -void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld, - struct hda_pcm_stream *hinfo) +void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, + struct hda_pcm_stream *codec_pars) { - u32 rates; - u64 formats; - unsigned int maxbps; - unsigned int channels_max; int i; /* assume basic audio support (the basic audio flag is not in ELD; * however, all audio capable sinks are required to support basic * audio) */ - rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000; - formats = SNDRV_PCM_FMTBIT_S16_LE; - maxbps = 16; - channels_max = 2; + pcm->rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; + pcm->formats = SNDRV_PCM_FMTBIT_S16_LE; + pcm->maxbps = 16; + pcm->channels_max = 2; for (i = 0; i < eld->sad_count; i++) { struct cea_sad *a = &eld->sad[i]; - rates |= a->rates; - if (a->channels > channels_max) - channels_max = a->channels; + pcm->rates |= a->rates; + if (a->channels > pcm->channels_max) + pcm->channels_max = a->channels; if (a->format == AUDIO_CODING_TYPE_LPCM) { if (a->sample_bits & AC_SUPPCM_BITS_20) { - formats |= SNDRV_PCM_FMTBIT_S32_LE; - if (maxbps < 20) - maxbps = 20; + pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE; + if (pcm->maxbps < 20) + pcm->maxbps = 20; } if (a->sample_bits & AC_SUPPCM_BITS_24) { - formats |= SNDRV_PCM_FMTBIT_S32_LE; - if (maxbps < 24) - maxbps = 24; + pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE; + if (pcm->maxbps < 24) + pcm->maxbps = 24; } } } + if (!codec_pars) + return; + /* restrict the parameters by the values the codec provides */ - hinfo->rates &= rates; - hinfo->formats &= formats; - hinfo->maxbps = min(hinfo->maxbps, maxbps); - hinfo->channels_max = min(hinfo->channels_max, channels_max); + pcm->rates &= codec_pars->rates; + pcm->formats &= codec_pars->formats; + pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max); + pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps); } diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index be6982289c0d..486f6deb3eee 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -177,8 +177,7 @@ MODULE_DESCRIPTION("Intel HDA driver"); #define ICH6_REG_INTCTL 0x20 #define ICH6_REG_INTSTS 0x24 #define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ -#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ -#define ICH6_REG_SSYNC 0x38 +#define ICH6_REG_SYNC 0x34 #define ICH6_REG_CORBLBASE 0x40 #define ICH6_REG_CORBUBASE 0x44 #define ICH6_REG_CORBWP 0x48 @@ -480,7 +479,6 @@ enum { #define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ #define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ #define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ -#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -1708,16 +1706,13 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; unsigned int bufsize, period_bytes, format_val, stream_tag; int err; - struct hda_spdif_out *spdif = - snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid); - unsigned short ctls = spdif ? spdif->ctls : 0; azx_stream_reset(chip, azx_dev); format_val = snd_hda_calc_stream_format(runtime->rate, runtime->channels, runtime->format, hinfo->maxbps, - ctls); + apcm->codec->spdif_ctls); if (!format_val) { snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n", @@ -1797,11 +1792,7 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&chip->reg_lock); if (nsync > 1) { /* first, set SYNC bits of corresponding streams */ - if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) - azx_writel(chip, OLD_SSYNC, - azx_readl(chip, OLD_SSYNC) | sbits); - else - azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits); + azx_writel(chip, SYNC, azx_readl(chip, SYNC) | sbits); } snd_pcm_group_for_each_entry(s, substream) { if (s->pcm->card != substream->pcm->card) @@ -1857,11 +1848,7 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (nsync > 1) { spin_lock(&chip->reg_lock); /* reset SYNC bits */ - if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) - azx_writel(chip, OLD_SSYNC, - azx_readl(chip, OLD_SSYNC) & ~sbits); - else - azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); + azx_writel(chip, SYNC, azx_readl(chip, SYNC) & ~sbits); spin_unlock(&chip->reg_lock); } return 0; @@ -1876,7 +1863,7 @@ static unsigned int azx_via_get_position(struct azx *chip, unsigned int fifo_size; link_pos = azx_sd_readl(azx_dev, SD_LPIB); - if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (azx_dev->index >= 4) { /* Playback, no problem using link position */ return link_pos; } @@ -1940,17 +1927,6 @@ static unsigned int azx_get_position(struct azx *chip, default: /* use the position buffer */ pos = le32_to_cpu(*azx_dev->posbuf); - if (chip->position_fix[stream] == POS_FIX_AUTO) { - if (!pos || pos == (u32)-1) { - printk(KERN_WARNING - "hda-intel: Invalid position buffer, " - "using LPIB read method instead.\n"); - chip->position_fix[stream] = POS_FIX_LPIB; - pos = azx_sd_readl(azx_dev, SD_LPIB); - } else - chip->position_fix[stream] = POS_FIX_POSBUF; - } - break; } if (pos >= azx_dev->bufsize) @@ -1988,6 +1964,16 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) stream = azx_dev->substream->stream; pos = azx_get_position(chip, azx_dev); + if (chip->position_fix[stream] == POS_FIX_AUTO) { + if (!pos) { + printk(KERN_WARNING + "hda-intel: Invalid position buffer, " + "using LPIB read method instead.\n"); + chip->position_fix[stream] = POS_FIX_LPIB; + pos = azx_get_position(chip, azx_dev); + } else + chip->position_fix[stream] = POS_FIX_POSBUF; + } if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) @@ -2075,8 +2061,6 @@ static void azx_pcm_free(struct snd_pcm *pcm) } } -#define MAX_PREALLOC_SIZE (32 * 1024 * 1024) - static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, struct hda_pcm *cpcm) @@ -2085,7 +2069,6 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, struct snd_pcm *pcm; struct azx_pcm *apcm; int pcm_dev = cpcm->device; - unsigned int size; int s, err; if (pcm_dev >= HDA_MAX_PCMS) { @@ -2121,12 +2104,9 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, snd_pcm_set_ops(pcm, s, &azx_pcm_ops); } /* buffer pre-allocation */ - size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; - if (size > MAX_PREALLOC_SIZE) - size = MAX_PREALLOC_SIZE; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), - size, MAX_PREALLOC_SIZE); + 1024 * 64, 32 * 1024 * 1024); return 0; } @@ -2169,7 +2149,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) { if (request_irq(chip->pci->irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "hda_intel", chip)) { printk(KERN_ERR "hda-intel: unable to grab IRQ %d, " "disabling device\n", chip->pci->irq); if (do_disconnect) @@ -2367,20 +2347,28 @@ static int azx_dev_free(struct snd_device *device) * white/black-listing for position_fix */ static struct snd_pci_quirk position_fix_list[] __devinitdata = { + SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1025, 0x026f, "Acer Aspire 5538", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1043, 0x8410, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB), SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB), SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), + SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), {} }; @@ -2827,22 +2815,6 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP }, - { PCI_DEVICE(0x8086, 0x2668), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH6 */ - { PCI_DEVICE(0x8086, 0x27d8), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH7 */ - { PCI_DEVICE(0x8086, 0x269a), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ESB2 */ - { PCI_DEVICE(0x8086, 0x284b), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH8 */ - { PCI_DEVICE(0x8086, 0x293e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */ - { PCI_DEVICE(0x8086, 0x293f), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */ - { PCI_DEVICE(0x8086, 0x3a3e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */ - { PCI_DEVICE(0x8086, 0x3a6e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */ /* Generic Intel */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, @@ -2936,7 +2908,7 @@ MODULE_DEVICE_TABLE(pci, azx_ids); /* pci_driver definition */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "HDA Intel", .id_table = azx_ids, .probe = azx_probe, .remove = __devexit_p(azx_remove), diff --git a/trunk/sound/pci/hda/hda_local.h b/trunk/sound/pci/hda/hda_local.h index 88b277e97409..08ec073444e2 100644 --- a/trunk/sound/pci/hda/hda_local.h +++ b/trunk/sound/pci/hda/hda_local.h @@ -212,9 +212,7 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, /* * SPDIF I/O */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t associated_nid, - hda_nid_t cvt_nid); +int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); /* @@ -565,6 +563,7 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) * power-management */ +#ifdef CONFIG_SND_HDA_POWER_SAVE void snd_hda_schedule_power_save(struct hda_codec *codec); struct hda_amp_list { @@ -581,6 +580,7 @@ struct hda_loopback_check { int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, hda_nid_t nid); +#endif /* CONFIG_SND_HDA_POWER_SAVE */ /* * AMP control callbacks @@ -639,8 +639,8 @@ struct hdmi_eld { int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); void snd_hdmi_show_eld(struct hdmi_eld *eld); -void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld, - struct hda_pcm_stream *hinfo); +void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, + struct hda_pcm_stream *codec_pars); #ifdef CONFIG_PROC_FS int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, diff --git a/trunk/sound/pci/hda/hda_proc.c b/trunk/sound/pci/hda/hda_proc.c index 2be57b051aa2..bfe74c2fb079 100644 --- a/trunk/sound/pci/hda/hda_proc.c +++ b/trunk/sound/pci/hda/hda_proc.c @@ -636,7 +636,7 @@ static void print_codec_info(struct snd_info_entry *entry, wid_caps |= AC_WCAP_CONN_LIST; if (wid_caps & AC_WCAP_CONN_LIST) - conn_len = snd_hda_get_raw_connections(codec, nid, conn, + conn_len = snd_hda_get_connections(codec, nid, conn, HDA_MAX_CONNECTIONS); if (wid_caps & AC_WCAP_IN_AMP) { diff --git a/trunk/sound/pci/hda/patch_analog.c b/trunk/sound/pci/hda/patch_analog.c index 1362c8ba4d1f..d694e9d4921d 100644 --- a/trunk/sound/pci/hda/patch_analog.c +++ b/trunk/sound/pci/hda/patch_analog.c @@ -213,9 +213,7 @@ static int ad198x_build_controls(struct hda_codec *codec) return err; } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, @@ -1922,8 +1920,7 @@ static int patch_ad1981(struct hda_codec *codec) spec->mixers[0] = ad1981_hp_mixers; spec->num_init_verbs = 2; spec->init_verbs[1] = ad1981_hp_init_verbs; - if (!is_jack_available(codec, 0x0a)) - spec->multiout.dig_out_nid = 0; + spec->multiout.dig_out_nid = 0; spec->input_mux = &ad1981_hp_capture_source; codec->patch_ops.init = ad1981_hp_init; diff --git a/trunk/sound/pci/hda/patch_ca0110.c b/trunk/sound/pci/hda/patch_ca0110.c index 6b406840846e..61b92634b161 100644 --- a/trunk/sound/pci/hda/patch_ca0110.c +++ b/trunk/sound/pci/hda/patch_ca0110.c @@ -240,8 +240,7 @@ static int ca0110_build_controls(struct hda_codec *codec) } if (spec->dig_out) { - err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, - spec->dig_out); + err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); diff --git a/trunk/sound/pci/hda/patch_ca0132.c b/trunk/sound/pci/hda/patch_ca0132.c deleted file mode 100644 index d9a2254ceef6..000000000000 --- a/trunk/sound/pci/hda/patch_ca0132.c +++ /dev/null @@ -1,1097 +0,0 @@ -/* - * HD audio interface patch for Creative CA0132 chip - * - * Copyright (c) 2011, Creative Technology Ltd. - * - * Based on patch_ca0110.c - * Copyright (c) 2008 Takashi Iwai - * - * This driver is free software; 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 driver 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 -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -#define WIDGET_CHIP_CTRL 0x15 -#define WIDGET_DSP_CTRL 0x16 - -#define WUH_MEM_CONNID 10 -#define DSP_MEM_CONNID 16 - -enum hda_cmd_vendor_io { - /* for DspIO node */ - VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000, - VENDOR_DSPIO_SCP_WRITE_DATA_HIGH = 0x100, - - VENDOR_DSPIO_STATUS = 0xF01, - VENDOR_DSPIO_SCP_POST_READ_DATA = 0x702, - VENDOR_DSPIO_SCP_READ_DATA = 0xF02, - VENDOR_DSPIO_DSP_INIT = 0x703, - VENDOR_DSPIO_SCP_POST_COUNT_QUERY = 0x704, - VENDOR_DSPIO_SCP_READ_COUNT = 0xF04, - - /* for ChipIO node */ - VENDOR_CHIPIO_ADDRESS_LOW = 0x000, - VENDOR_CHIPIO_ADDRESS_HIGH = 0x100, - VENDOR_CHIPIO_STREAM_FORMAT = 0x200, - VENDOR_CHIPIO_DATA_LOW = 0x300, - VENDOR_CHIPIO_DATA_HIGH = 0x400, - - VENDOR_CHIPIO_GET_PARAMETER = 0xF00, - VENDOR_CHIPIO_STATUS = 0xF01, - VENDOR_CHIPIO_HIC_POST_READ = 0x702, - VENDOR_CHIPIO_HIC_READ_DATA = 0xF03, - - VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE = 0x70A, - - VENDOR_CHIPIO_PLL_PMU_WRITE = 0x70C, - VENDOR_CHIPIO_PLL_PMU_READ = 0xF0C, - VENDOR_CHIPIO_8051_ADDRESS_LOW = 0x70D, - VENDOR_CHIPIO_8051_ADDRESS_HIGH = 0x70E, - VENDOR_CHIPIO_FLAG_SET = 0x70F, - VENDOR_CHIPIO_FLAGS_GET = 0xF0F, - VENDOR_CHIPIO_PARAMETER_SET = 0x710, - VENDOR_CHIPIO_PARAMETER_GET = 0xF10, - - VENDOR_CHIPIO_PORT_ALLOC_CONFIG_SET = 0x711, - VENDOR_CHIPIO_PORT_ALLOC_SET = 0x712, - VENDOR_CHIPIO_PORT_ALLOC_GET = 0xF12, - VENDOR_CHIPIO_PORT_FREE_SET = 0x713, - - VENDOR_CHIPIO_PARAMETER_EX_ID_GET = 0xF17, - VENDOR_CHIPIO_PARAMETER_EX_ID_SET = 0x717, - VENDOR_CHIPIO_PARAMETER_EX_VALUE_GET = 0xF18, - VENDOR_CHIPIO_PARAMETER_EX_VALUE_SET = 0x718 -}; - -/* - * Control flag IDs - */ -enum control_flag_id { - /* Connection manager stream setup is bypassed/enabled */ - CONTROL_FLAG_C_MGR = 0, - /* DSP DMA is bypassed/enabled */ - CONTROL_FLAG_DMA = 1, - /* 8051 'idle' mode is disabled/enabled */ - CONTROL_FLAG_IDLE_ENABLE = 2, - /* Tracker for the SPDIF-in path is bypassed/enabled */ - CONTROL_FLAG_TRACKER = 3, - /* DigitalOut to Spdif2Out connection is disabled/enabled */ - CONTROL_FLAG_SPDIF2OUT = 4, - /* Digital Microphone is disabled/enabled */ - CONTROL_FLAG_DMIC = 5, - /* ADC_B rate is 48 kHz/96 kHz */ - CONTROL_FLAG_ADC_B_96KHZ = 6, - /* ADC_C rate is 48 kHz/96 kHz */ - CONTROL_FLAG_ADC_C_96KHZ = 7, - /* DAC rate is 48 kHz/96 kHz (affects all DACs) */ - CONTROL_FLAG_DAC_96KHZ = 8, - /* DSP rate is 48 kHz/96 kHz */ - CONTROL_FLAG_DSP_96KHZ = 9, - /* SRC clock is 98 MHz/196 MHz (196 MHz forces rate to 96 KHz) */ - CONTROL_FLAG_SRC_CLOCK_196MHZ = 10, - /* SRC rate is 48 kHz/96 kHz (48 kHz disabled when clock is 196 MHz) */ - CONTROL_FLAG_SRC_RATE_96KHZ = 11, - /* Decode Loop (DSP->SRC->DSP) is disabled/enabled */ - CONTROL_FLAG_DECODE_LOOP = 12, - /* De-emphasis filter on DAC-1 disabled/enabled */ - CONTROL_FLAG_DAC1_DEEMPHASIS = 13, - /* De-emphasis filter on DAC-2 disabled/enabled */ - CONTROL_FLAG_DAC2_DEEMPHASIS = 14, - /* De-emphasis filter on DAC-3 disabled/enabled */ - CONTROL_FLAG_DAC3_DEEMPHASIS = 15, - /* High-pass filter on ADC_B disabled/enabled */ - CONTROL_FLAG_ADC_B_HIGH_PASS = 16, - /* High-pass filter on ADC_C disabled/enabled */ - CONTROL_FLAG_ADC_C_HIGH_PASS = 17, - /* Common mode on Port_A disabled/enabled */ - CONTROL_FLAG_PORT_A_COMMON_MODE = 18, - /* Common mode on Port_D disabled/enabled */ - CONTROL_FLAG_PORT_D_COMMON_MODE = 19, - /* Impedance for ramp generator on Port_A 16 Ohm/10K Ohm */ - CONTROL_FLAG_PORT_A_10KOHM_LOAD = 20, - /* Impedance for ramp generator on Port_D, 16 Ohm/10K Ohm */ - CONTROL_FLAG_PORT_D_10K0HM_LOAD = 21, - /* ASI rate is 48kHz/96kHz */ - CONTROL_FLAG_ASI_96KHZ = 22, - /* DAC power settings able to control attached ports no/yes */ - CONTROL_FLAG_DACS_CONTROL_PORTS = 23, - /* Clock Stop OK reporting is disabled/enabled */ - CONTROL_FLAG_CONTROL_STOP_OK_ENABLE = 24, - /* Number of control flags */ - CONTROL_FLAGS_MAX = (CONTROL_FLAG_CONTROL_STOP_OK_ENABLE+1) -}; - -/* - * Control parameter IDs - */ -enum control_parameter_id { - /* 0: force HDA, 1: allow DSP if HDA Spdif1Out stream is idle */ - CONTROL_PARAM_SPDIF1_SOURCE = 2, - - /* Stream Control */ - - /* Select stream with the given ID */ - CONTROL_PARAM_STREAM_ID = 24, - /* Source connection point for the selected stream */ - CONTROL_PARAM_STREAM_SOURCE_CONN_POINT = 25, - /* Destination connection point for the selected stream */ - CONTROL_PARAM_STREAM_DEST_CONN_POINT = 26, - /* Number of audio channels in the selected stream */ - CONTROL_PARAM_STREAMS_CHANNELS = 27, - /*Enable control for the selected stream */ - CONTROL_PARAM_STREAM_CONTROL = 28, - - /* Connection Point Control */ - - /* Select connection point with the given ID */ - CONTROL_PARAM_CONN_POINT_ID = 29, - /* Connection point sample rate */ - CONTROL_PARAM_CONN_POINT_SAMPLE_RATE = 30, - - /* Node Control */ - - /* Select HDA node with the given ID */ - CONTROL_PARAM_NODE_ID = 31 -}; - -/* - * Dsp Io Status codes - */ -enum hda_vendor_status_dspio { - /* Success */ - VENDOR_STATUS_DSPIO_OK = 0x00, - /* Busy, unable to accept new command, the host must retry */ - VENDOR_STATUS_DSPIO_BUSY = 0x01, - /* SCP command queue is full */ - VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL = 0x02, - /* SCP response queue is empty */ - VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY = 0x03 -}; - -/* - * Chip Io Status codes - */ -enum hda_vendor_status_chipio { - /* Success */ - VENDOR_STATUS_CHIPIO_OK = 0x00, - /* Busy, unable to accept new command, the host must retry */ - VENDOR_STATUS_CHIPIO_BUSY = 0x01 -}; - -/* - * CA0132 sample rate - */ -enum ca0132_sample_rate { - SR_6_000 = 0x00, - SR_8_000 = 0x01, - SR_9_600 = 0x02, - SR_11_025 = 0x03, - SR_16_000 = 0x04, - SR_22_050 = 0x05, - SR_24_000 = 0x06, - SR_32_000 = 0x07, - SR_44_100 = 0x08, - SR_48_000 = 0x09, - SR_88_200 = 0x0A, - SR_96_000 = 0x0B, - SR_144_000 = 0x0C, - SR_176_400 = 0x0D, - SR_192_000 = 0x0E, - SR_384_000 = 0x0F, - - SR_COUNT = 0x10, - - SR_RATE_UNKNOWN = 0x1F -}; - -/* - * Scp Helper function - */ -enum get_set { - IS_SET = 0, - IS_GET = 1, -}; - -/* - * Duplicated from ca0110 codec - */ - -static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) -{ - if (pin) { - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - } - if (dac) - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); -} - -static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) -{ - if (pin) { - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_VREF80); - if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } - if (adc) - snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); -} - -static char *dirstr[2] = { "Playback", "Capture" }; - -static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0) -#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0) -#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1) -#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1) -#define add_mono_switch(codec, nid, pfx, chan) \ - _add_switch(codec, nid, pfx, chan, 0) -#define add_mono_volume(codec, nid, pfx, chan) \ - _add_volume(codec, nid, pfx, chan, 0) -#define add_in_mono_switch(codec, nid, pfx, chan) \ - _add_switch(codec, nid, pfx, chan, 1) -#define add_in_mono_volume(codec, nid, pfx, chan) \ - _add_volume(codec, nid, pfx, chan, 1) - - -/* - * CA0132 specific - */ - -struct ca0132_spec { - struct auto_pin_cfg autocfg; - struct hda_multi_out multiout; - hda_nid_t out_pins[AUTO_CFG_MAX_OUTS]; - hda_nid_t dacs[AUTO_CFG_MAX_OUTS]; - hda_nid_t hp_dac; - hda_nid_t input_pins[AUTO_PIN_LAST]; - hda_nid_t adcs[AUTO_PIN_LAST]; - hda_nid_t dig_out; - hda_nid_t dig_in; - unsigned int num_inputs; - long curr_hp_switch; - long curr_hp_volume[2]; - long curr_speaker_switch; - struct mutex chipio_mutex; - const char *input_labels[AUTO_PIN_LAST]; - struct hda_pcm pcm_rec[2]; /* PCM information */ -}; - -/* Chip access helper function */ -static int chipio_send(struct hda_codec *codec, - unsigned int reg, - unsigned int data) -{ - unsigned int res; - int retry = 50; - - /* send bits of data specified by reg */ - do { - res = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0, - reg, data); - if (res == VENDOR_STATUS_CHIPIO_OK) - return 0; - } while (--retry); - return -EIO; -} - -/* - * Write chip address through the vendor widget -- NOT protected by the Mutex! - */ -static int chipio_write_address(struct hda_codec *codec, - unsigned int chip_addx) -{ - int res; - - /* send low 16 bits of the address */ - res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_LOW, - chip_addx & 0xffff); - - if (res != -EIO) { - /* send high 16 bits of the address */ - res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_HIGH, - chip_addx >> 16); - } - - return res; -} - -/* - * Write data through the vendor widget -- NOT protected by the Mutex! - */ - -static int chipio_write_data(struct hda_codec *codec, unsigned int data) -{ - int res; - - /* send low 16 bits of the data */ - res = chipio_send(codec, VENDOR_CHIPIO_DATA_LOW, data & 0xffff); - - if (res != -EIO) { - /* send high 16 bits of the data */ - res = chipio_send(codec, VENDOR_CHIPIO_DATA_HIGH, - data >> 16); - } - - return res; -} - -/* - * Read data through the vendor widget -- NOT protected by the Mutex! - */ -static int chipio_read_data(struct hda_codec *codec, unsigned int *data) -{ - int res; - - /* post read */ - res = chipio_send(codec, VENDOR_CHIPIO_HIC_POST_READ, 0); - - if (res != -EIO) { - /* read status */ - res = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0); - } - - if (res != -EIO) { - /* read data */ - *data = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_HIC_READ_DATA, - 0); - } - - return res; -} - -/* - * Write given value to the given address through the chip I/O widget. - * protected by the Mutex - */ -static int chipio_write(struct hda_codec *codec, - unsigned int chip_addx, const unsigned int data) -{ - struct ca0132_spec *spec = codec->spec; - int err; - - mutex_lock(&spec->chipio_mutex); - - /* write the address, and if successful proceed to write data */ - err = chipio_write_address(codec, chip_addx); - if (err < 0) - goto exit; - - err = chipio_write_data(codec, data); - if (err < 0) - goto exit; - -exit: - mutex_unlock(&spec->chipio_mutex); - return err; -} - -/* - * Read the given address through the chip I/O widget - * protected by the Mutex - */ -static int chipio_read(struct hda_codec *codec, - unsigned int chip_addx, unsigned int *data) -{ - struct ca0132_spec *spec = codec->spec; - int err; - - mutex_lock(&spec->chipio_mutex); - - /* write the address, and if successful proceed to write data */ - err = chipio_write_address(codec, chip_addx); - if (err < 0) - goto exit; - - err = chipio_read_data(codec, data); - if (err < 0) - goto exit; - -exit: - mutex_unlock(&spec->chipio_mutex); - return err; -} - -/* - * PCM stuffs - */ -static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid, - u32 stream_tag, - int channel_id, int format) -{ - unsigned int oldval, newval; - - if (!nid) - return; - - snd_printdd("ca0132_setup_stream: " - "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", - nid, stream_tag, channel_id, format); - - /* update the format-id if changed */ - oldval = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_STREAM_FORMAT, - 0); - if (oldval != format) { - msleep(20); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_STREAM_FORMAT, - format); - } - - oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); - newval = (stream_tag << 4) | channel_id; - if (oldval != newval) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, - newval); - } -} - -static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) -{ - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); -} - -/* - * PCM callbacks - */ -static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); - - return 0; -} - -static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_cleanup_stream(codec, spec->dacs[0]); - - return 0; -} - -/* - * Digital out - */ -static int ca0132_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_setup_stream(codec, spec->dig_out, stream_tag, 0, format); - - return 0; -} - -static int ca0132_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_cleanup_stream(codec, spec->dig_out); - - return 0; -} - -/* - * Analog capture - */ -static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_setup_stream(codec, spec->adcs[substream->number], - stream_tag, 0, format); - - return 0; -} - -static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_cleanup_stream(codec, spec->adcs[substream->number]); - - return 0; -} - -/* - * Digital capture - */ -static int ca0132_dig_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_setup_stream(codec, spec->dig_in, stream_tag, 0, format); - - return 0; -} - -static int ca0132_dig_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0132_spec *spec = codec->spec; - - ca0132_cleanup_stream(codec, spec->dig_in); - - return 0; -} - -/* - */ -static struct hda_pcm_stream ca0132_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0132_playback_pcm_prepare, - .cleanup = ca0132_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ca0132_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0132_capture_pcm_prepare, - .cleanup = ca0132_capture_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ca0132_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0132_dig_playback_pcm_prepare, - .cleanup = ca0132_dig_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ca0132_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0132_dig_capture_pcm_prepare, - .cleanup = ca0132_dig_capture_pcm_cleanup - }, -}; - -static int ca0132_build_pcms(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->pcm_info = info; - codec->num_pcms = 0; - - info->name = "CA0132 Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; - codec->num_pcms++; - - if (!spec->dig_out && !spec->dig_in) - return 0; - - info++; - info->name = "CA0132 Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->dig_out) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - ca0132_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; - } - if (spec->dig_in) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - ca0132_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; - } - codec->num_pcms++; - - return 0; -} - -#define REG_CODEC_MUTE 0x18b014 -#define REG_CODEC_HP_VOL_L 0x18b070 -#define REG_CODEC_HP_VOL_R 0x18b074 - -static int ca0132_hp_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - - *valp = spec->curr_hp_switch; - return 0; -} - -static int ca0132_hp_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - unsigned int data; - int err; - - /* any change? */ - if (spec->curr_hp_switch == *valp) - return 0; - - snd_hda_power_up(codec); - - err = chipio_read(codec, REG_CODEC_MUTE, &data); - if (err < 0) - return err; - - /* *valp 0 is mute, 1 is unmute */ - data = (data & 0x7f) | (*valp ? 0 : 0x80); - chipio_write(codec, REG_CODEC_MUTE, data); - if (err < 0) - return err; - - spec->curr_hp_switch = *valp; - - snd_hda_power_down(codec); - return 1; -} - -static int ca0132_speaker_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - - *valp = spec->curr_speaker_switch; - return 0; -} - -static int ca0132_speaker_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - unsigned int data; - int err; - - /* any change? */ - if (spec->curr_speaker_switch == *valp) - return 0; - - snd_hda_power_up(codec); - - err = chipio_read(codec, REG_CODEC_MUTE, &data); - if (err < 0) - return err; - - /* *valp 0 is mute, 1 is unmute */ - data = (data & 0xef) | (*valp ? 0 : 0x10); - chipio_write(codec, REG_CODEC_MUTE, data); - if (err < 0) - return err; - - spec->curr_speaker_switch = *valp; - - snd_hda_power_down(codec); - return 1; -} - -static int ca0132_hp_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - - *valp++ = spec->curr_hp_volume[0]; - *valp = spec->curr_hp_volume[1]; - return 0; -} - -static int ca0132_hp_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - long left_vol, right_vol; - unsigned int data; - int val; - int err; - - left_vol = *valp++; - right_vol = *valp; - - /* any change? */ - if ((spec->curr_hp_volume[0] == left_vol) && - (spec->curr_hp_volume[1] == right_vol)) - return 0; - - snd_hda_power_up(codec); - - err = chipio_read(codec, REG_CODEC_HP_VOL_L, &data); - if (err < 0) - return err; - - val = 31 - left_vol; - data = (data & 0xe0) | val; - chipio_write(codec, REG_CODEC_HP_VOL_L, data); - if (err < 0) - return err; - - val = 31 - right_vol; - data = (data & 0xe0) | val; - chipio_write(codec, REG_CODEC_HP_VOL_R, data); - if (err < 0) - return err; - - spec->curr_hp_volume[0] = left_vol; - spec->curr_hp_volume[1] = right_vol; - - snd_hda_power_down(codec); - return 1; -} - -static int add_hp_switch(struct hda_codec *codec, hda_nid_t nid) -{ - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO("Headphone Playback Switch", - nid, 1, 0, HDA_OUTPUT); - knew.get = ca0132_hp_switch_get; - knew.put = ca0132_hp_switch_put; - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static int add_hp_volume(struct hda_codec *codec, hda_nid_t nid) -{ - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO("Headphone Playback Volume", - nid, 3, 0, HDA_OUTPUT); - knew.get = ca0132_hp_volume_get; - knew.put = ca0132_hp_volume_put; - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static int add_speaker_switch(struct hda_codec *codec, hda_nid_t nid) -{ - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", - nid, 1, 0, HDA_OUTPUT); - knew.get = ca0132_speaker_switch_get; - knew.put = ca0132_speaker_switch_put; - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static void ca0132_fix_hp_caps(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int caps; - - /* set mute-capable, 1db step, 32 steps, ofs 6 */ - caps = 0x80031f06; - snd_hda_override_amp_caps(codec, cfg->hp_pins[0], HDA_OUTPUT, caps); -} - -static int ca0132_build_controls(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - - if (spec->multiout.num_dacs) { - err = add_speaker_switch(codec, spec->out_pins[0]); - if (err < 0) - return err; - } - - if (cfg->hp_outs) { - ca0132_fix_hp_caps(codec); - err = add_hp_switch(codec, cfg->hp_pins[0]); - if (err < 0) - return err; - err = add_hp_volume(codec, cfg->hp_pins[0]); - if (err < 0) - return err; - } - - for (i = 0; i < spec->num_inputs; i++) { - const char *label = spec->input_labels[i]; - - err = add_in_switch(codec, spec->adcs[i], label); - if (err < 0) - return err; - err = add_in_volume(codec, spec->adcs[i], label); - if (err < 0) - return err; - if (cfg->inputs[i].type == AUTO_PIN_MIC) { - /* add Mic-Boost */ - err = add_in_mono_volume(codec, spec->input_pins[i], - "Mic Boost", 1); - if (err < 0) - return err; - } - } - - if (spec->dig_out) { - err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, - spec->dig_out); - if (err < 0) - return err; - err = add_out_volume(codec, spec->dig_out, "IEC958"); - if (err < 0) - return err; - } - - if (spec->dig_in) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); - if (err < 0) - return err; - err = add_in_volume(codec, spec->dig_in, "IEC958"); - } - return 0; -} - - -static void ca0132_set_ct_ext(struct hda_codec *codec, int enable) -{ - /* Set Creative extension */ - snd_printdd("SET CREATIVE EXTENSION\n"); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, - enable); - msleep(20); -} - - -static void ca0132_config(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - /* line-outs */ - cfg->line_outs = 1; - cfg->line_out_pins[0] = 0x0b; /* front */ - cfg->line_out_type = AUTO_PIN_LINE_OUT; - - spec->dacs[0] = 0x02; - spec->out_pins[0] = 0x0b; - spec->multiout.dac_nids = spec->dacs; - spec->multiout.num_dacs = 1; - spec->multiout.max_channels = 2; - - /* headphone */ - cfg->hp_outs = 1; - cfg->hp_pins[0] = 0x0f; - - spec->hp_dac = 0; - spec->multiout.hp_nid = 0; - - /* inputs */ - cfg->num_inputs = 2; /* Mic-in and line-in */ - cfg->inputs[0].pin = 0x12; - cfg->inputs[0].type = AUTO_PIN_MIC; - cfg->inputs[1].pin = 0x11; - cfg->inputs[1].type = AUTO_PIN_LINE_IN; - - /* Mic-in */ - spec->input_pins[0] = 0x12; - spec->input_labels[0] = "Mic-In"; - spec->adcs[0] = 0x07; - - /* Line-In */ - spec->input_pins[1] = 0x11; - spec->input_labels[1] = "Line-In"; - spec->adcs[1] = 0x08; - spec->num_inputs = 2; -} - -static void ca0132_init_chip(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - - mutex_init(&spec->chipio_mutex); -} - -static void ca0132_exit_chip(struct hda_codec *codec) -{ - /* put any chip cleanup stuffs here. */ -} - -static int ca0132_init(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - init_output(codec, spec->out_pins[i], - spec->multiout.dac_nids[i]); - } - init_output(codec, cfg->hp_pins[0], spec->hp_dac); - init_output(codec, cfg->dig_out_pins[0], spec->dig_out); - - for (i = 0; i < spec->num_inputs; i++) - init_input(codec, spec->input_pins[i], spec->adcs[i]); - - init_input(codec, cfg->dig_in_pin, spec->dig_in); - - ca0132_set_ct_ext(codec, 1); - - return 0; -} - - -static void ca0132_free(struct hda_codec *codec) -{ - ca0132_set_ct_ext(codec, 0); - ca0132_exit_chip(codec); - kfree(codec->spec); -} - -static struct hda_codec_ops ca0132_patch_ops = { - .build_controls = ca0132_build_controls, - .build_pcms = ca0132_build_pcms, - .init = ca0132_init, - .free = ca0132_free, -}; - - - -static int patch_ca0132(struct hda_codec *codec) -{ - struct ca0132_spec *spec; - - snd_printdd("patch_ca0132\n"); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - - ca0132_init_chip(codec); - - ca0132_config(codec); - - codec->patch_ops = ca0132_patch_ops; - - return 0; -} - -/* - * patch entries - */ -static struct hda_codec_preset snd_hda_preset_ca0132[] = { - { .id = 0x11020011, .name = "CA0132", .patch = patch_ca0132 }, - {} /* terminator */ -}; - -MODULE_ALIAS("snd-hda-codec-id:11020011"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Creative CA0132, CA0132 HD-audio codec"); - -static struct hda_codec_preset_list ca0132_list = { - .preset = snd_hda_preset_ca0132, - .owner = THIS_MODULE, -}; - -static int __init patch_ca0132_init(void) -{ - return snd_hda_add_codec_preset(&ca0132_list); -} - -static void __exit patch_ca0132_exit(void) -{ - snd_hda_delete_codec_preset(&ca0132_list); -} - -module_init(patch_ca0132_init) -module_exit(patch_ca0132_exit) diff --git a/trunk/sound/pci/hda/patch_cirrus.c b/trunk/sound/pci/hda/patch_cirrus.c index 7f93739b1e33..26a1521045bb 100644 --- a/trunk/sound/pci/hda/patch_cirrus.c +++ b/trunk/sound/pci/hda/patch_cirrus.c @@ -346,15 +346,21 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, nid = codec->start_nid; for (i = 0; i < codec->num_nodes; i++, nid++) { + hda_nid_t pins[2]; unsigned int type; - int idx; + int j, nums; type = get_wcaps_type(get_wcaps(codec, nid)); if (type != AC_WID_AUD_IN) continue; - idx = snd_hda_get_conn_index(codec, nid, pin, 0); - if (idx >= 0) { - *idxp = idx; - return nid; + nums = snd_hda_get_connections(codec, nid, pins, + ARRAY_SIZE(pins)); + if (nums <= 0) + continue; + for (j = 0; j < nums; j++) { + if (pins[j] == pin) { + *idxp = j; + return nid; + } } } return 0; @@ -815,8 +821,7 @@ static int build_digital_output(struct hda_codec *codec) if (!spec->multiout.dig_out_nid) return 0; - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); diff --git a/trunk/sound/pci/hda/patch_cmedia.c b/trunk/sound/pci/hda/patch_cmedia.c index cd2cf5e94e81..ab3308daa960 100644 --- a/trunk/sound/pci/hda/patch_cmedia.c +++ b/trunk/sound/pci/hda/patch_cmedia.c @@ -327,9 +327,7 @@ static int cmi9880_build_controls(struct hda_codec *codec) return err; } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, @@ -398,11 +396,12 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi { struct cmi_spec *spec = codec->spec; hda_nid_t nid; - int i, j, k; + int i, j, k, len; /* clear the table, only one c-media dac assumed here */ memset(spec->multi_init, 0, sizeof(spec->multi_init)); for (j = 0, i = 0; i < cfg->line_outs; i++) { + hda_nid_t conn[4]; nid = cfg->line_out_pins[i]; /* set as output */ spec->multi_init[j].nid = nid; @@ -415,10 +414,12 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; spec->multi_init[j].param = 0; /* find the index in connect list */ - k = snd_hda_get_conn_index(codec, nid, - spec->dac_nids[i], 0); - if (k >= 0) - spec->multi_init[j].param = k; + len = snd_hda_get_connections(codec, nid, conn, 4); + for (k = 0; k < len; k++) + if (conn[k] == spec->dac_nids[i]) { + spec->multi_init[j].param = k; + break; + } j++; } } diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index 884f67b8f4e0..7bbc5f237a5e 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -155,10 +155,6 @@ struct conexant_spec { unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ unsigned int beep_amp; - - /* extra EAPD pins */ - unsigned int num_eapds; - hda_nid_t eapds[4]; }; static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, @@ -514,7 +510,6 @@ static int conexant_build_controls(struct hda_codec *codec) } if (spec->multiout.dig_out_nid) { err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, spec->multiout.dig_out_nid); if (err < 0) return err; @@ -1128,8 +1123,10 @@ static int patch_cxt5045(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, cxt5045_models, cxt5045_cfg_tbl); +#if 0 /* use the old method just for safety */ if (board_config < 0) - board_config = CXT5045_AUTO; /* model=auto as default */ + board_config = CXT5045_AUTO; +#endif if (board_config == CXT5045_AUTO) return patch_conexant_auto(codec); @@ -1567,8 +1564,10 @@ static int patch_cxt5047(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, cxt5047_models, cxt5047_cfg_tbl); +#if 0 /* not enabled as default, as BIOS often broken for this codec */ if (board_config < 0) - board_config = CXT5047_AUTO; /* model=auto as default */ + board_config = CXT5047_AUTO; +#endif if (board_config == CXT5047_AUTO) return patch_conexant_auto(codec); @@ -1994,8 +1993,10 @@ static int patch_cxt5051(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, cxt5051_models, cxt5051_cfg_tbl); +#if 0 /* use the old method just for safety */ if (board_config < 0) - board_config = CXT5051_AUTO; /* model=auto as default */ + board_config = CXT5051_AUTO; +#endif if (board_config == CXT5051_AUTO) return patch_conexant_auto(codec); @@ -3113,8 +3114,10 @@ static int patch_cxt5066(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, cxt5066_models, cxt5066_cfg_tbl); +#if 0 /* use the old method just for safety */ if (board_config < 0) - board_config = CXT5066_AUTO; /* model=auto as default */ + board_config = CXT5066_AUTO; +#endif if (board_config == CXT5066_AUTO) return patch_conexant_auto(codec); @@ -3305,8 +3308,19 @@ static const struct hda_pcm_stream cx_auto_pcm_analog_capture = { static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; -#define get_connection_index(codec, mux, nid)\ - snd_hda_get_conn_index(codec, mux, nid, 0) +/* get the connection index of @nid in the widget @mux */ +static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t nid) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == nid) + return i; + return -1; +} /* get an unassigned DAC from the given list. * Return the nid if found and reduce the DAC list, or return zero if @@ -3905,38 +3919,6 @@ static void cx_auto_parse_beep(struct hda_codec *codec) #define cx_auto_parse_beep(codec) #endif -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return true; - return false; -} - -/* parse extra-EAPD that aren't assigned to any pins */ -static void cx_auto_parse_eapd(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid, end_nid; - - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) - continue; - if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) - continue; - if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) || - found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) || - found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs)) - continue; - spec->eapds[spec->num_eapds++] = nid; - if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) - break; - } -} - static int cx_auto_parse_auto_config(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -3950,7 +3932,6 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec) cx_auto_parse_input(codec); cx_auto_parse_digital(codec); cx_auto_parse_beep(codec); - cx_auto_parse_eapd(codec); return 0; } @@ -4038,8 +4019,6 @@ static void cx_auto_init_output(struct hda_codec *codec) } } cx_auto_update_speakers(codec); - /* turn on/off extra EAPDs, too */ - cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); } static void cx_auto_init_input(struct hda_codec *codec) diff --git a/trunk/sound/pci/hda/patch_hdmi.c b/trunk/sound/pci/hda/patch_hdmi.c index 19cb72db9c38..bd0ae697f9c4 100644 --- a/trunk/sound/pci/hda/patch_hdmi.c +++ b/trunk/sound/pci/hda/patch_hdmi.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); /* * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device - * could support N independent pipes, each of them can be connected to one or + * could support two independent pipes, each of them can be connected to one or * more ports (DVI, HDMI or DisplayPort). * * The HDA correspondence of pipes/ports are converter/pin nodes. @@ -51,33 +51,30 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); #define MAX_HDMI_CVTS 4 #define MAX_HDMI_PINS 4 -struct hdmi_spec_per_cvt { - hda_nid_t cvt_nid; - int assigned; - unsigned int channels_min; - unsigned int channels_max; - u32 rates; - u64 formats; - unsigned int maxbps; -}; - -struct hdmi_spec_per_pin { - hda_nid_t pin_nid; - int num_mux_nids; - hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; - struct hdmi_eld sink_eld; -}; - struct hdmi_spec { int num_cvts; - struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS]; - int num_pins; - struct hdmi_spec_per_pin pins[MAX_HDMI_PINS]; - struct hda_pcm pcm_rec[MAX_HDMI_PINS]; + hda_nid_t cvt[MAX_HDMI_CVTS+1]; /* audio sources */ + hda_nid_t pin[MAX_HDMI_PINS+1]; /* audio sinks */ + + /* + * source connection for each pin + */ + hda_nid_t pin_cvt[MAX_HDMI_PINS+1]; /* - * Non-generic ATI/NVIDIA specific + * HDMI sink attached to each pin + */ + struct hdmi_eld sink_eld[MAX_HDMI_PINS]; + + /* + * export one pcm per pipe + */ + struct hda_pcm pcm_rec[MAX_HDMI_CVTS]; + struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS]; + + /* + * ati/nvhdmi specific */ struct hda_multi_out multiout; const struct hda_pcm_stream *pcm_playback; @@ -287,40 +284,15 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { * HDMI routines */ -static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid) -{ - int pin_idx; - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) - if (spec->pins[pin_idx].pin_nid == pin_nid) - return pin_idx; - - snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid); - return -EINVAL; -} - -static int hinfo_to_pin_index(struct hdmi_spec *spec, - struct hda_pcm_stream *hinfo) -{ - int pin_idx; - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) - if (&spec->pcm_rec[pin_idx].stream[0] == hinfo) - return pin_idx; - - snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo); - return -EINVAL; -} - -static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid) +static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) { - int cvt_idx; + int i; - for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) - if (spec->cvts[cvt_idx].cvt_nid == cvt_nid) - return cvt_idx; + for (i = 0; nids[i]; i++) + if (nids[i] == nid) + return i; - snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid); + snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid); return -EINVAL; } @@ -354,28 +326,28 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid, snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); } -static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid) +static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid) { /* Unmute */ if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* Disable pin out until stream is active*/ + /* Enable pin out */ snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); } -static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid) +static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid) { - return 1 + snd_hda_codec_read(codec, cvt_nid, 0, + return 1 + snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CVT_CHAN_COUNT, 0); } static void hdmi_set_channel_count(struct hda_codec *codec, - hda_nid_t cvt_nid, int chs) + hda_nid_t nid, int chs) { - if (chs != hdmi_get_channel_count(codec, cvt_nid)) - snd_hda_codec_write(codec, cvt_nid, 0, + if (chs != hdmi_get_channel_count(codec, nid)) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); } @@ -412,8 +384,11 @@ static void init_channel_allocations(void) * * TODO: it could select the wrong CA from multiple candidates. */ -static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) +static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid, + int channels) { + struct hdmi_spec *spec = codec->spec; + struct hdmi_eld *eld; int i; int ca = 0; int spk_mask = 0; @@ -425,6 +400,19 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) if (channels <= 2) return 0; + i = hda_node_index(spec->pin_cvt, nid); + if (i < 0) + return 0; + eld = &spec->sink_eld[i]; + + /* + * HDMI sink's ELD info cannot always be retrieved for now, e.g. + * in console or for audio devices. Assume the highest speakers + * configuration, to _not_ prohibit multi-channel audio playback. + */ + if (!eld->spk_alloc) + eld->spk_alloc = 0xffff; + /* * expand ELD's speaker allocation mask * @@ -620,63 +608,67 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, return true; } -static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, +static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, struct snd_pcm_substream *substream) { struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - hda_nid_t pin_nid = per_pin->pin_nid; + hda_nid_t pin_nid; int channels = substream->runtime->channels; - struct hdmi_eld *eld; int ca; + int i; union audio_infoframe ai; - eld = &spec->pins[pin_idx].sink_eld; - if (!eld->monitor_present) - return; + ca = hdmi_channel_allocation(codec, nid, channels); - ca = hdmi_channel_allocation(eld, channels); - - memset(&ai, 0, sizeof(ai)); - if (eld->conn_type == 0) { /* HDMI */ - struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi; - - hdmi_ai->type = 0x84; - hdmi_ai->ver = 0x01; - hdmi_ai->len = 0x0a; - hdmi_ai->CC02_CT47 = channels - 1; - hdmi_ai->CA = ca; - hdmi_checksum_audio_infoframe(hdmi_ai); - } else if (eld->conn_type == 1) { /* DisplayPort */ - struct dp_audio_infoframe *dp_ai = &ai.dp; - - dp_ai->type = 0x84; - dp_ai->len = 0x1b; - dp_ai->ver = 0x11 << 2; - dp_ai->CC02_CT47 = channels - 1; - dp_ai->CA = ca; - } else { - snd_printd("HDMI: unknown connection type at pin %d\n", - pin_nid); - return; - } + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_cvt[i] != nid) + continue; + if (!spec->sink_eld[i].monitor_present) + continue; - /* - * sizeof(ai) is used instead of sizeof(*hdmi_ai) or - * sizeof(*dp_ai) to avoid partial match/update problems when - * the user switches between HDMI/DP monitors. - */ - if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes, - sizeof(ai))) { - snd_printdd("hdmi_setup_audio_infoframe: " - "pin=%d channels=%d\n", - pin_nid, - channels); - hdmi_setup_channel_mapping(codec, pin_nid, ca); - hdmi_stop_infoframe_trans(codec, pin_nid); - hdmi_fill_audio_infoframe(codec, pin_nid, - ai.bytes, sizeof(ai)); - hdmi_start_infoframe_trans(codec, pin_nid); + pin_nid = spec->pin[i]; + + memset(&ai, 0, sizeof(ai)); + if (spec->sink_eld[i].conn_type == 0) { /* HDMI */ + struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi; + + hdmi_ai->type = 0x84; + hdmi_ai->ver = 0x01; + hdmi_ai->len = 0x0a; + hdmi_ai->CC02_CT47 = channels - 1; + hdmi_ai->CA = ca; + hdmi_checksum_audio_infoframe(hdmi_ai); + } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */ + struct dp_audio_infoframe *dp_ai = &ai.dp; + + dp_ai->type = 0x84; + dp_ai->len = 0x1b; + dp_ai->ver = 0x11 << 2; + dp_ai->CC02_CT47 = channels - 1; + dp_ai->CA = ca; + } else { + snd_printd("HDMI: unknown connection type at pin %d\n", + pin_nid); + continue; + } + + /* + * sizeof(ai) is used instead of sizeof(*hdmi_ai) or + * sizeof(*dp_ai) to avoid partial match/update problems when + * the user switches between HDMI/DP monitors. + */ + if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes, + sizeof(ai))) { + snd_printdd("hdmi_setup_audio_infoframe: " + "cvt=%d pin=%d channels=%d\n", + nid, pin_nid, + channels); + hdmi_setup_channel_mapping(codec, pin_nid, ca); + hdmi_stop_infoframe_trans(codec, pin_nid); + hdmi_fill_audio_infoframe(codec, pin_nid, + ai.bytes, sizeof(ai)); + hdmi_start_infoframe_trans(codec, pin_nid); + } } } @@ -694,27 +686,17 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT; int pd = !!(res & AC_UNSOL_RES_PD); int eldv = !!(res & AC_UNSOL_RES_ELDV); - int pin_idx; - struct hdmi_eld *eld; + int index; printk(KERN_INFO - "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - codec->addr, pin_nid, pd, eldv); + "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", + pin_nid, pd, eldv); - pin_idx = pin_nid_to_pin_index(spec, pin_nid); - if (pin_idx < 0) + index = hda_node_index(spec->pin, pin_nid); + if (index < 0) return; - eld = &spec->pins[pin_idx].sink_eld; - hdmi_present_sense(codec, pin_nid, eld); - - /* - * HDMI sink's ELD info cannot always be retrieved for now, e.g. - * in console or for audio devices. Assume the highest speakers - * configuration, to _not_ prohibit multi-channel audio playback. - */ - if (!eld->spk_alloc) - eld->spk_alloc = 0xffff; + hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]); } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) @@ -725,8 +707,7 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); printk(KERN_INFO - "HDMI CP event: CODEC=%d PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", - codec->addr, + "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", tag, subtag, cp_state, @@ -746,7 +727,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; - if (pin_nid_to_pin_index(spec, tag) < 0) { + if (hda_node_index(spec->pin, tag) < 0) { snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); return; } @@ -765,14 +746,21 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) #define is_hbr_format(format) \ ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7) -static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format) +static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, + u32 stream_tag, int format) { + struct hdmi_spec *spec = codec->spec; int pinctl; int new_pinctl = 0; + int i; + + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_cvt[i] != nid) + continue; + if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR)) + continue; - if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) { - pinctl = snd_hda_codec_read(codec, pin_nid, 0, + pinctl = snd_hda_codec_read(codec, spec->pin[i], 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); new_pinctl = pinctl & ~AC_PINCTL_EPT; @@ -783,22 +771,22 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, snd_printdd("hdmi_setup_stream: " "NID=0x%x, %spinctl=0x%x\n", - pin_nid, + spec->pin[i], pinctl == new_pinctl ? "" : "new-", new_pinctl); if (pinctl != new_pinctl) - snd_hda_codec_write(codec, pin_nid, 0, + snd_hda_codec_write(codec, spec->pin[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_pinctl); - } + if (is_hbr_format(format) && !new_pinctl) { snd_printdd("hdmi_setup_stream: HBR is not supported\n"); return -EINVAL; } - snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); return 0; } @@ -810,70 +798,37 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct hdmi_spec *spec = codec->spec; - struct snd_pcm_runtime *runtime = substream->runtime; - int pin_idx, cvt_idx, mux_idx = 0; - struct hdmi_spec_per_pin *per_pin; struct hdmi_eld *eld; - struct hdmi_spec_per_cvt *per_cvt = NULL; - int pinctl; + struct hda_pcm_stream *codec_pars; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int idx; - /* Validate hinfo */ - pin_idx = hinfo_to_pin_index(spec, hinfo); - if (snd_BUG_ON(pin_idx < 0)) + for (idx = 0; idx < spec->num_cvts; idx++) + if (hinfo->nid == spec->cvt[idx]) + break; + if (snd_BUG_ON(idx >= spec->num_cvts) || + snd_BUG_ON(idx >= spec->num_pins)) return -EINVAL; - per_pin = &spec->pins[pin_idx]; - eld = &per_pin->sink_eld; - /* Dynamically assign converter to stream */ - for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { - per_cvt = &spec->cvts[cvt_idx]; + /* save the PCM info the codec provides */ + codec_pars = &spec->codec_pcm_pars[idx]; + if (!codec_pars->rates) + *codec_pars = *hinfo; - /* Must not already be assigned */ - if (per_cvt->assigned) - continue; - /* Must be in pin's mux's list of converters */ - for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++) - if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid) - break; - /* Not in mux list */ - if (mux_idx == per_pin->num_mux_nids) - continue; - break; - } - /* No free converters */ - if (cvt_idx == spec->num_cvts) - return -ENODEV; - - /* Claim converter */ - per_cvt->assigned = 1; - hinfo->nid = per_cvt->cvt_nid; - - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_CONNECT_SEL, - mux_idx); - pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinctl | PIN_OUT); - snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid); - - /* Initially set the converter's capabilities */ - hinfo->channels_min = per_cvt->channels_min; - hinfo->channels_max = per_cvt->channels_max; - hinfo->rates = per_cvt->rates; - hinfo->formats = per_cvt->formats; - hinfo->maxbps = per_cvt->maxbps; - - /* Restrict capabilities by ELD if this isn't disabled */ - if (!static_hdmi_pcm && eld->eld_valid) { - snd_hdmi_eld_update_pcm_info(eld, hinfo); + eld = &spec->sink_eld[idx]; + if (!static_hdmi_pcm && eld->eld_valid && eld->sad_count > 0) { + hdmi_eld_update_pcm_info(eld, hinfo, codec_pars); if (hinfo->channels_min > hinfo->channels_max || !hinfo->rates || !hinfo->formats) return -ENODEV; + } else { + /* fallback to the codec default */ + hinfo->channels_max = codec_pars->channels_max; + hinfo->rates = codec_pars->rates; + hinfo->formats = codec_pars->formats; + hinfo->maxbps = codec_pars->maxbps; } - - /* Store the updated parameters */ + /* store the updated parameters */ runtime->hw.channels_min = hinfo->channels_min; runtime->hw.channels_max = hinfo->channels_max; runtime->hw.formats = hinfo->formats; @@ -887,11 +842,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, /* * HDA/HDMI auto parsing */ -static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) +static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) { struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - hda_nid_t pin_nid = per_pin->pin_nid; + hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; + int conn_len, curr; + int index; if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { snd_printk(KERN_WARNING @@ -901,9 +857,19 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) return -EINVAL; } - per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid, - per_pin->mux_nids, - HDA_MAX_CONNECTIONS); + conn_len = snd_hda_get_connections(codec, pin_nid, conn_list, + HDA_MAX_CONNECTIONS); + if (conn_len > 1) + curr = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + else + curr = 0; + + index = hda_node_index(spec->pin, pin_nid); + if (index < 0) + return -EINVAL; + + spec->pin_cvt[index] = conn_list[curr]; return 0; } @@ -930,8 +896,8 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, eld->eld_valid = 0; printk(KERN_INFO - "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - codec->addr, pin_nid, eld->monitor_present, eld->eld_valid); + "HDMI status: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", + pin_nid, eld->monitor_present, eld->eld_valid); if (eld->eld_valid) if (!snd_hdmi_get_eld(eld, codec, pin_nid)) @@ -943,75 +909,47 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) { struct hdmi_spec *spec = codec->spec; - unsigned int caps, config; - int pin_idx; - struct hdmi_spec_per_pin *per_pin; - struct hdmi_eld *eld; int err; - caps = snd_hda_param_read(codec, pin_nid, AC_PAR_PIN_CAP); - if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) - return 0; - - config = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); - if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) - return 0; - - if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS)) + if (spec->num_pins >= MAX_HDMI_PINS) { + snd_printk(KERN_WARNING + "HDMI: no space for pin %d\n", pin_nid); return -E2BIG; - - pin_idx = spec->num_pins; - per_pin = &spec->pins[pin_idx]; - eld = &per_pin->sink_eld; - - per_pin->pin_nid = pin_nid; + } err = snd_hda_input_jack_add(codec, pin_nid, SND_JACK_VIDEOOUT, NULL); if (err < 0) return err; - err = hdmi_read_pin_conn(codec, pin_idx); - if (err < 0) - return err; + hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); + spec->pin[spec->num_pins] = pin_nid; spec->num_pins++; - hdmi_present_sense(codec, pin_nid, eld); - - return 0; + return hdmi_read_pin_conn(codec, pin_nid); } -static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) +static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) { + int i, found_pin = 0; struct hdmi_spec *spec = codec->spec; - int cvt_idx; - struct hdmi_spec_per_cvt *per_cvt; - unsigned int chans; - int err; - - if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS)) - return -E2BIG; - - chans = get_wcaps(codec, cvt_nid); - chans = get_wcaps_channels(chans); - cvt_idx = spec->num_cvts; - per_cvt = &spec->cvts[cvt_idx]; + for (i = 0; i < spec->num_pins; i++) + if (nid == spec->pin_cvt[i]) { + found_pin = 1; + break; + } - per_cvt->cvt_nid = cvt_nid; - per_cvt->channels_min = 2; - if (chans <= 16) - per_cvt->channels_max = chans; + if (!found_pin) { + snd_printdd("HDMI: Skipping node %d (no connection)\n", nid); + return -EINVAL; + } - err = snd_hda_query_supported_pcm(codec, cvt_nid, - &per_cvt->rates, - &per_cvt->formats, - &per_cvt->maxbps); - if (err < 0) - return err; + if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS)) + return -E2BIG; + spec->cvt[spec->num_cvts] = nid; spec->num_cvts++; return 0; @@ -1021,6 +959,8 @@ static int hdmi_parse_codec(struct hda_codec *codec) { hda_nid_t nid; int i, nodes; + int num_tmp_cvts = 0; + hda_nid_t tmp_cvt[MAX_HDMI_CVTS]; nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); if (!nid || nodes < 0) { @@ -1031,6 +971,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) for (i = 0; i < nodes; i++, nid++) { unsigned int caps; unsigned int type; + unsigned int config; caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); type = get_wcaps_type(caps); @@ -1040,14 +981,32 @@ static int hdmi_parse_codec(struct hda_codec *codec) switch (type) { case AC_WID_AUD_OUT: - hdmi_add_cvt(codec, nid); + if (num_tmp_cvts >= MAX_HDMI_CVTS) { + snd_printk(KERN_WARNING + "HDMI: no space for converter %d\n", nid); + continue; + } + tmp_cvt[num_tmp_cvts] = nid; + num_tmp_cvts++; break; case AC_WID_PIN: + caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); + if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) + continue; + + config = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) + continue; + hdmi_add_pin(codec, nid); break; } } + for (i = 0; i < num_tmp_cvts; i++) + hdmi_add_cvt(codec, tmp_cvt[i]); + /* * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event * can be lost and presence sense verb will become inaccurate if the @@ -1064,7 +1023,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) /* */ -static char *generic_hdmi_pcm_names[MAX_HDMI_PINS] = { +static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = { "HDMI 0", "HDMI 1", "HDMI 2", @@ -1081,84 +1040,51 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, unsigned int format, struct snd_pcm_substream *substream) { - hda_nid_t cvt_nid = hinfo->nid; - struct hdmi_spec *spec = codec->spec; - int pin_idx = hinfo_to_pin_index(spec, hinfo); - hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid; - - hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); + hdmi_set_channel_count(codec, hinfo->nid, + substream->runtime->channels); - hdmi_setup_audio_infoframe(codec, pin_idx, substream); + hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); - return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); + return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); } -static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct hdmi_spec *spec = codec->spec; - int cvt_idx, pin_idx; - struct hdmi_spec_per_cvt *per_cvt; - struct hdmi_spec_per_pin *per_pin; - int pinctl; - - snd_hda_codec_cleanup_stream(codec, hinfo->nid); - - if (hinfo->nid) { - cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); - if (snd_BUG_ON(cvt_idx < 0)) - return -EINVAL; - per_cvt = &spec->cvts[cvt_idx]; - - snd_BUG_ON(!per_cvt->assigned); - per_cvt->assigned = 0; - hinfo->nid = 0; - - pin_idx = hinfo_to_pin_index(spec, hinfo); - if (snd_BUG_ON(pin_idx < 0)) - return -EINVAL; - per_pin = &spec->pins[pin_idx]; - - pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinctl & ~PIN_OUT); - snd_hda_spdif_ctls_unassign(codec, pin_idx); - } - - return 0; -} - -static const struct hda_pcm_ops generic_ops = { - .open = hdmi_pcm_open, - .prepare = generic_hdmi_playback_pcm_prepare, - .cleanup = generic_hdmi_playback_pcm_cleanup, +static const struct hda_pcm_stream generic_hdmi_pcm_playback = { + .substreams = 1, + .channels_min = 2, + .ops = { + .open = hdmi_pcm_open, + .prepare = generic_hdmi_playback_pcm_prepare, + }, }; static int generic_hdmi_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - int pin_idx; + struct hda_pcm *info = spec->pcm_rec; + int i; - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hda_pcm *info; + codec->num_pcms = spec->num_cvts; + codec->pcm_info = info; + + for (i = 0; i < codec->num_pcms; i++, info++) { + unsigned int chans; struct hda_pcm_stream *pstr; - info = &spec->pcm_rec[pin_idx]; - info->name = generic_hdmi_pcm_names[pin_idx]; - info->pcm_type = HDA_PCM_TYPE_HDMI; + chans = get_wcaps(codec, spec->cvt[i]); + chans = get_wcaps_channels(chans); + info->name = generic_hdmi_pcm_names[i]; + info->pcm_type = HDA_PCM_TYPE_HDMI; pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; - pstr->substreams = 1; - pstr->ops = generic_ops; - /* other pstr fields are set in open */ + if (spec->pcm_playback) + *pstr = *spec->pcm_playback; + else + *pstr = generic_hdmi_pcm_playback; + pstr->nid = spec->cvt[i]; + if (pstr->channels_max <= 2 && chans && chans <= 16) + pstr->channels_max = chans; } - codec->num_pcms = spec->num_pins; - codec->pcm_info = spec->pcm_rec; - return 0; } @@ -1166,16 +1092,12 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int err; - int pin_idx; + int i; - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - err = snd_hda_create_spdif_out_ctls(codec, - per_pin->pin_nid, - per_pin->mux_nids[0]); + for (i = 0; i < codec->num_pcms; i++) { + err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]); if (err < 0) return err; - snd_hda_spdif_ctls_unassign(codec, pin_idx); } return 0; @@ -1184,19 +1106,13 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) static int generic_hdmi_init(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - int pin_idx; - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - hda_nid_t pin_nid = per_pin->pin_nid; - struct hdmi_eld *eld = &per_pin->sink_eld; + int i; - hdmi_init_pin(codec, pin_nid); - snd_hda_codec_write(codec, pin_nid, 0, + for (i = 0; spec->pin[i]; i++) { + hdmi_enable_output(codec, spec->pin[i]); + snd_hda_codec_write(codec, spec->pin[i], 0, AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | pin_nid); - - snd_hda_eld_proc_new(codec, eld, pin_idx); + AC_USRSP_EN | spec->pin[i]); } return 0; } @@ -1204,14 +1120,10 @@ static int generic_hdmi_init(struct hda_codec *codec) static void generic_hdmi_free(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - int pin_idx; - - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - struct hdmi_eld *eld = &per_pin->sink_eld; + int i; - snd_hda_eld_proc_free(codec, eld); - } + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); snd_hda_input_jack_free(codec); kfree(spec); @@ -1228,6 +1140,7 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { static int patch_generic_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; + int i; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -1241,68 +1154,14 @@ static int patch_generic_hdmi(struct hda_codec *codec) } codec->patch_ops = generic_hdmi_patch_ops; - init_channel_allocations(); - - return 0; -} - -/* - * Shared non-generic implementations - */ - -static int simple_playback_build_pcms(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - int i; - - codec->num_pcms = spec->num_cvts; - codec->pcm_info = info; - - for (i = 0; i < codec->num_pcms; i++, info++) { - unsigned int chans; - struct hda_pcm_stream *pstr; - - chans = get_wcaps(codec, spec->cvts[i].cvt_nid); - chans = get_wcaps_channels(chans); - - info->name = generic_hdmi_pcm_names[i]; - info->pcm_type = HDA_PCM_TYPE_HDMI; - pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; - snd_BUG_ON(!spec->pcm_playback); - *pstr = *spec->pcm_playback; - pstr->nid = spec->cvts[i].cvt_nid; - if (pstr->channels_max <= 2 && chans && chans <= 16) - pstr->channels_max = chans; - } - - return 0; -} - -static int simple_playback_build_controls(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int err; - int i; + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); - for (i = 0; i < codec->num_pcms; i++) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->cvts[i].cvt_nid, - spec->cvts[i].cvt_nid); - if (err < 0) - return err; - } + init_channel_allocations(); return 0; } -static void simple_playback_free(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - - kfree(spec); -} - /* * Nvidia specific implementations */ @@ -1493,9 +1352,6 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, int chs; unsigned int dataDCC1, dataDCC2, channel_id; int i; - struct hdmi_spec *spec = codec->spec; - struct hda_spdif_out *spdif = - snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid); mutex_lock(&codec->spdif_mutex); @@ -1505,12 +1361,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, dataDCC2 = 0x2; /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & ~AC_DIG1_ENABLE & 0xff); + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); /* set the stream id */ snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, @@ -1522,12 +1378,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, /* turn on again (if needed) */ /* enable and set the channel status audio/data flag */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) { + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & 0xff); + codec->spdif_ctls & 0xff); snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, @@ -1544,12 +1400,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, *otherwise the IEC958 bits won't be updated */ if (codec->spdif_status_reset && - (spdif->ctls & AC_DIG1_ENABLE)) + (codec->spdif_ctls & AC_DIG1_ENABLE)) snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & ~AC_DIG1_ENABLE & 0xff); + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); /* set the stream id */ snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], @@ -1565,12 +1421,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, /* turn on again (if needed) */ /* enable and set the channel status audio/data flag */ if (codec->spdif_status_reset && - (spdif->ctls & AC_DIG1_ENABLE)) { + (codec->spdif_ctls & AC_DIG1_ENABLE)) { snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_DIGI_CONVERT_1, - spdif->ctls & 0xff); + codec->spdif_ctls & 0xff); snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, @@ -1615,17 +1471,17 @@ static const struct hda_pcm_stream nvhdmi_pcm_playback_2ch = { }; static const struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { - .build_controls = simple_playback_build_controls, - .build_pcms = simple_playback_build_pcms, + .build_controls = generic_hdmi_build_controls, + .build_pcms = generic_hdmi_build_pcms, .init = nvhdmi_7x_init, - .free = simple_playback_free, + .free = generic_hdmi_free, }; static const struct hda_codec_ops nvhdmi_patch_ops_2ch = { - .build_controls = simple_playback_build_controls, - .build_pcms = simple_playback_build_pcms, + .build_controls = generic_hdmi_build_controls, + .build_pcms = generic_hdmi_build_pcms, .init = nvhdmi_7x_init, - .free = simple_playback_free, + .free = generic_hdmi_free, }; static int patch_nvhdmi_2ch(struct hda_codec *codec) @@ -1642,7 +1498,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) spec->multiout.max_channels = 2; spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; spec->num_cvts = 1; - spec->cvts[0].cvt_nid = nvhdmi_master_con_nid_7x; + spec->cvt[0] = nvhdmi_master_con_nid_7x; spec->pcm_playback = &nvhdmi_pcm_playback_2ch; codec->patch_ops = nvhdmi_patch_ops_2ch; @@ -1693,11 +1549,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, substream); if (err < 0) return err; - snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0, - AC_VERB_SET_CVT_CHAN_COUNT, chans - 1); + snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT, + chans - 1); /* FIXME: XXX */ for (i = 0; i < chans; i++) { - snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0, + snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_HDMI_CHAN_SLOT, (i << 4) | i); } @@ -1728,18 +1584,18 @@ static int atihdmi_init(struct hda_codec *codec) snd_hda_sequence_write(codec, atihdmi_basic_init); /* SI codec requires to unmute the pin */ - if (get_wcaps(codec, spec->pins[0].pin_nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, spec->pins[0].pin_nid, 0, + if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, spec->pin[0], 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); return 0; } static const struct hda_codec_ops atihdmi_patch_ops = { - .build_controls = simple_playback_build_controls, - .build_pcms = simple_playback_build_pcms, + .build_controls = generic_hdmi_build_controls, + .build_pcms = generic_hdmi_build_pcms, .init = atihdmi_init, - .free = simple_playback_free, + .free = generic_hdmi_free, }; @@ -1757,8 +1613,8 @@ static int patch_atihdmi(struct hda_codec *codec) spec->multiout.max_channels = 2; spec->multiout.dig_out_nid = ATIHDMI_CVT_NID; spec->num_cvts = 1; - spec->cvts[0].cvt_nid = ATIHDMI_CVT_NID; - spec->pins[0].pin_nid = ATIHDMI_PIN_NID; + spec->cvt[0] = ATIHDMI_CVT_NID; + spec->pin[0] = ATIHDMI_PIN_NID; spec->pcm_playback = &atihdmi_pcm_digital_playback; codec->patch_ops = atihdmi_patch_ops; diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 52ce07534e5b..b48fb43b5448 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -1,7 +1,7 @@ /* * Universal Interface for Intel High Definition Audio Codec * - * HD audio interface patch for Realtek ALC codecs + * HD audio interface patch for ALC 260/880/882 codecs * * Copyright (c) 2004 Kailang Yang * PeiSen Hou @@ -33,11 +33,236 @@ #include "hda_local.h" #include "hda_beep.h" -/* unsol event tags */ -#define ALC_FRONT_EVENT 0x01 -#define ALC_DCVOL_EVENT 0x02 -#define ALC_HP_EVENT 0x04 -#define ALC_MIC_EVENT 0x08 +#define ALC880_FRONT_EVENT 0x01 +#define ALC880_DCVOL_EVENT 0x02 +#define ALC880_HP_EVENT 0x04 +#define ALC880_MIC_EVENT 0x08 + +/* ALC880 board config type */ +enum { + ALC880_3ST, + ALC880_3ST_DIG, + ALC880_5ST, + ALC880_5ST_DIG, + ALC880_W810, + ALC880_Z71V, + ALC880_6ST, + ALC880_6ST_DIG, + ALC880_F1734, + ALC880_ASUS, + ALC880_ASUS_DIG, + ALC880_ASUS_W1V, + ALC880_ASUS_DIG2, + ALC880_FUJITSU, + ALC880_UNIWILL_DIG, + ALC880_UNIWILL, + ALC880_UNIWILL_P53, + ALC880_CLEVO, + ALC880_TCL_S700, + ALC880_LG, + ALC880_LG_LW, + ALC880_MEDION_RIM, +#ifdef CONFIG_SND_DEBUG + ALC880_TEST, +#endif + ALC880_AUTO, + ALC880_MODEL_LAST /* last tag */ +}; + +/* ALC260 models */ +enum { + ALC260_BASIC, + ALC260_HP, + ALC260_HP_DC7600, + ALC260_HP_3013, + ALC260_FUJITSU_S702X, + ALC260_ACER, + ALC260_WILL, + ALC260_REPLACER_672V, + ALC260_FAVORIT100, +#ifdef CONFIG_SND_DEBUG + ALC260_TEST, +#endif + ALC260_AUTO, + ALC260_MODEL_LAST /* last tag */ +}; + +/* ALC262 models */ +enum { + ALC262_BASIC, + ALC262_HIPPO, + ALC262_HIPPO_1, + ALC262_FUJITSU, + ALC262_HP_BPC, + ALC262_HP_BPC_D7000_WL, + ALC262_HP_BPC_D7000_WF, + ALC262_HP_TC_T5735, + ALC262_HP_RP5700, + ALC262_BENQ_ED8, + ALC262_SONY_ASSAMD, + ALC262_BENQ_T31, + ALC262_ULTRA, + ALC262_LENOVO_3000, + ALC262_NEC, + ALC262_TOSHIBA_S06, + ALC262_TOSHIBA_RX1, + ALC262_TYAN, + ALC262_AUTO, + ALC262_MODEL_LAST /* last tag */ +}; + +/* ALC268 models */ +enum { + ALC267_QUANTA_IL1, + ALC268_3ST, + ALC268_TOSHIBA, + ALC268_ACER, + ALC268_ACER_DMIC, + ALC268_ACER_ASPIRE_ONE, + ALC268_DELL, + ALC268_ZEPTO, +#ifdef CONFIG_SND_DEBUG + ALC268_TEST, +#endif + ALC268_AUTO, + ALC268_MODEL_LAST /* last tag */ +}; + +/* ALC269 models */ +enum { + ALC269_BASIC, + ALC269_QUANTA_FL1, + ALC269_AMIC, + ALC269_DMIC, + ALC269VB_AMIC, + ALC269VB_DMIC, + ALC269_FUJITSU, + ALC269_LIFEBOOK, + ALC271_ACER, + ALC269_AUTO, + ALC269_MODEL_LAST /* last tag */ +}; + +/* ALC861 models */ +enum { + ALC861_3ST, + ALC660_3ST, + ALC861_3ST_DIG, + ALC861_6ST_DIG, + ALC861_UNIWILL_M31, + ALC861_TOSHIBA, + ALC861_ASUS, + ALC861_ASUS_LAPTOP, + ALC861_AUTO, + ALC861_MODEL_LAST, +}; + +/* ALC861-VD models */ +enum { + ALC660VD_3ST, + ALC660VD_3ST_DIG, + ALC660VD_ASUS_V1S, + ALC861VD_3ST, + ALC861VD_3ST_DIG, + ALC861VD_6ST_DIG, + ALC861VD_LENOVO, + ALC861VD_DALLAS, + ALC861VD_HP, + ALC861VD_AUTO, + ALC861VD_MODEL_LAST, +}; + +/* ALC662 models */ +enum { + ALC662_3ST_2ch_DIG, + ALC662_3ST_6ch_DIG, + ALC662_3ST_6ch, + ALC662_5ST_DIG, + ALC662_LENOVO_101E, + ALC662_ASUS_EEEPC_P701, + ALC662_ASUS_EEEPC_EP20, + ALC663_ASUS_M51VA, + ALC663_ASUS_G71V, + ALC663_ASUS_H13, + ALC663_ASUS_G50V, + ALC662_ECS, + ALC663_ASUS_MODE1, + ALC662_ASUS_MODE2, + ALC663_ASUS_MODE3, + ALC663_ASUS_MODE4, + ALC663_ASUS_MODE5, + ALC663_ASUS_MODE6, + ALC663_ASUS_MODE7, + ALC663_ASUS_MODE8, + ALC272_DELL, + ALC272_DELL_ZM1, + ALC272_SAMSUNG_NC10, + ALC662_AUTO, + ALC662_MODEL_LAST, +}; + +/* ALC882 models */ +enum { + ALC882_3ST_DIG, + ALC882_6ST_DIG, + ALC882_ARIMA, + ALC882_W2JC, + ALC882_TARGA, + ALC882_ASUS_A7J, + ALC882_ASUS_A7M, + ALC885_MACPRO, + ALC885_MBA21, + ALC885_MBP3, + ALC885_MB5, + ALC885_MACMINI3, + ALC885_IMAC24, + ALC885_IMAC91, + ALC883_3ST_2ch_DIG, + ALC883_3ST_6ch_DIG, + ALC883_3ST_6ch, + ALC883_6ST_DIG, + ALC883_TARGA_DIG, + ALC883_TARGA_2ch_DIG, + ALC883_TARGA_8ch_DIG, + ALC883_ACER, + ALC883_ACER_ASPIRE, + ALC888_ACER_ASPIRE_4930G, + ALC888_ACER_ASPIRE_6530G, + ALC888_ACER_ASPIRE_8930G, + ALC888_ACER_ASPIRE_7730G, + ALC883_MEDION, + ALC883_MEDION_WIM2160, + ALC883_LAPTOP_EAPD, + ALC883_LENOVO_101E_2ch, + ALC883_LENOVO_NB0763, + ALC888_LENOVO_MS7195_DIG, + ALC888_LENOVO_SKY, + ALC883_HAIER_W66, + ALC888_3ST_HP, + ALC888_6ST_DELL, + ALC883_MITAC, + ALC883_CLEVO_M540R, + ALC883_CLEVO_M720, + ALC883_FUJITSU_PI2515, + ALC888_FUJITSU_XA3530, + ALC883_3ST_6ch_INTEL, + ALC889A_INTEL, + ALC889_INTEL, + ALC888_ASUS_M90V, + ALC888_ASUS_EEE1601, + ALC889A_MB31, + ALC1200_ASUS_P5Q, + ALC883_SONY_VAIO_TT, + ALC882_AUTO, + ALC882_MODEL_LAST, +}; + +/* ALC680 models */ +enum { + ALC680_BASE, + ALC680_AUTO, + ALC680_MODEL_LAST, +}; /* for GPIO Poll */ #define GPIO_MASK 0x03 @@ -51,6 +276,14 @@ enum { ALC_INIT_GPIO3, }; +struct alc_mic_route { + hda_nid_t pin; + unsigned char mux_idx; + unsigned char amix_idx; +}; + +#define MUX_IDX_UNDEF ((unsigned char)-1) + struct alc_customize_define { unsigned int sku_cfg; unsigned char port_connectivity; @@ -115,9 +348,9 @@ struct alc_spec { const hda_nid_t *adc_nids; const hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ - hda_nid_t mixer_nid; /* analog-mixer NID */ /* capture setup for dynamic dual-adc switch */ + unsigned int cur_adc_idx; hda_nid_t cur_adc; unsigned int cur_adc_stream_tag; unsigned int cur_adc_format; @@ -126,9 +359,9 @@ struct alc_spec { unsigned int num_mux_defs; const struct hda_input_mux *input_mux; unsigned int cur_mux[3]; - hda_nid_t ext_mic_pin; - hda_nid_t dock_mic_pin; - hda_nid_t int_mic_pin; + struct alc_mic_route ext_mic; + struct alc_mic_route dock_mic; + struct alc_mic_route int_mic; /* channel model */ const struct hda_channel_mode *channel_mode; @@ -148,9 +381,6 @@ struct alc_spec { hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS]; - hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; - unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; - int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */ /* hooks */ void (*init_hook)(struct hda_codec *codec); @@ -165,7 +395,6 @@ struct alc_spec { unsigned int line_jack_present:1; unsigned int master_mute:1; unsigned int auto_mic:1; - unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */ unsigned int automute:1; /* HP automute enabled */ unsigned int detect_line:1; /* Line-out detection enabled */ unsigned int automute_lines:1; /* automute line-out as well */ @@ -173,9 +402,8 @@ struct alc_spec { /* other flags */ unsigned int no_analog :1; /* digital I/O only */ - unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */ + unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ unsigned int single_input_src:1; - unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ /* auto-mute control */ int automute_mode; @@ -204,23 +432,39 @@ struct alc_spec { struct alc_multi_io multi_io[4]; }; -#define ALC_MODEL_AUTO 0 /* common for all chips */ - -static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, - int dir, unsigned int bits) -{ - if (!nid) - return false; - if (get_wcaps(codec, nid) & (1 << (dir + 1))) - if (query_amp_caps(codec, nid, dir) & bits) - return true; - return false; -} +/* + * configuration template - to be copied to the spec instance + */ +struct alc_config_preset { + const struct snd_kcontrol_new *mixers[5]; /* should be identical size + * with spec + */ + const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ + const struct hda_verb *init_verbs[5]; + unsigned int num_dacs; + const hda_nid_t *dac_nids; + hda_nid_t dig_out_nid; /* optional */ + hda_nid_t hp_nid; /* optional */ + const hda_nid_t *slave_dig_outs; + unsigned int num_adc_nids; + const hda_nid_t *adc_nids; + const hda_nid_t *capsrc_nids; + hda_nid_t dig_in_nid; + unsigned int num_channel_mode; + const struct hda_channel_mode *channel_mode; + int need_dac_fix; + int const_channel_count; + unsigned int num_mux_defs; + const struct hda_input_mux *input_mux; + void (*unsol_event)(struct hda_codec *, unsigned int); + void (*setup)(struct hda_codec *); + void (*init_hook)(struct hda_codec *); +#ifdef CONFIG_SND_HDA_POWER_SAVE + const struct hda_amp_list *loopbacks; + void (*power_hook)(struct hda_codec *codec); +#endif +}; -#define nid_has_mute(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) -#define nid_has_volume(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) /* * input MUX handling @@ -249,83 +493,388 @@ static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, return 0; } -static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; - - if (spec->cur_adc && spec->cur_adc != new_adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = new_adc; - snd_hda_codec_setup_stream(codec, new_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - return true; - } - return false; -} - -/* select the given imux item; either unmute exclusively or select the route */ -static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, - unsigned int idx, bool force) +static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; const struct hda_input_mux *imux; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); unsigned int mux_idx; - int i, type; - hda_nid_t nid; + hda_nid_t nid = spec->capsrc_nids ? + spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; + unsigned int type; mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; if (!imux->num_items && mux_idx > 0) imux = &spec->input_mux[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (spec->cur_mux[adc_idx] == idx && !force) - return 0; - spec->cur_mux[adc_idx] = idx; - - if (spec->dyn_adc_switch) { - alc_dyn_adc_pcm_resetup(codec, idx); - adc_idx = spec->dyn_adc_idx[idx]; - } - - nid = spec->capsrc_nids ? - spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; - - /* no selection? */ - if (snd_hda_get_conn_list(codec, nid, NULL) <= 1) - return 1; - type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_AUD_MIX) { /* Matrix-mixer style (e.g. ALC882) */ + unsigned int *cur_val = &spec->cur_mux[adc_idx]; + unsigned int i, idx; + + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (*cur_val == idx) + return 0; for (i = 0; i < imux->num_items; i++) { unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, imux->items[i].index, HDA_AMP_MUTE, v); } + *cur_val = idx; + return 1; } else { /* MUX style (e.g. ALC880) */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[idx].index); + return snd_hda_input_mux_put(codec, imux, ucontrol, nid, + &spec->cur_mux[adc_idx]); } - return 1; } -static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, +/* + * channel mode setting + */ +static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, + spec->num_channel_mode); +} + +static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, + spec->num_channel_mode, + spec->ext_channel_count); +} + +static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, + spec->num_channel_mode, + &spec->ext_channel_count); + if (err >= 0 && !spec->const_channel_count) { + spec->multiout.max_channels = spec->ext_channel_count; + if (spec->need_dac_fix) + spec->multiout.num_dacs = spec->multiout.max_channels / 2; + } + return err; +} + +/* + * Control the mode of pin widget settings via the mixer. "pc" is used + * instead of "%" to avoid consequences of accidentally treating the % as + * being part of a format specifier. Maximum allowed length of a value is + * 63 characters plus NULL terminator. + * + * Note: some retasking pin complexes seem to ignore requests for input + * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these + * are requested. Therefore order this list so that this behaviour will not + * cause problems when mixer clients move through the enum sequentially. + * NIDs 0x0f and 0x10 have been observed to have this behaviour as of + * March 2006. + */ +static const char * const alc_pin_mode_names[] = { + "Mic 50pc bias", "Mic 80pc bias", + "Line in", "Line out", "Headphone out", +}; +static const unsigned char alc_pin_mode_values[] = { + PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP, +}; +/* The control can present all 5 options, or it can limit the options based + * in the pin being assumed to be exclusively an input or an output pin. In + * addition, "input" pins may or may not process the mic bias option + * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to + * accept requests for bias as of chip versions up to March 2006) and/or + * wiring in the computer. + */ +#define ALC_PIN_DIR_IN 0x00 +#define ALC_PIN_DIR_OUT 0x01 +#define ALC_PIN_DIR_INOUT 0x02 +#define ALC_PIN_DIR_IN_NOMICBIAS 0x03 +#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04 + +/* Info about the pin modes supported by the different pin direction modes. + * For each direction the minimum and maximum values are given. + */ +static const signed char alc_pin_mode_dir_info[5][2] = { + { 0, 2 }, /* ALC_PIN_DIR_IN */ + { 3, 4 }, /* ALC_PIN_DIR_OUT */ + { 0, 4 }, /* ALC_PIN_DIR_INOUT */ + { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */ + { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */ +}; +#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0]) +#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1]) +#define alc_pin_mode_n_items(_dir) \ + (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1) + +static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int item_num = uinfo->value.enumerated.item; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = alc_pin_mode_n_items(dir); + + if (item_numalc_pin_mode_max(dir)) + item_num = alc_pin_mode_min(dir); + strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]); + return 0; +} + +static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + unsigned int i; struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return alc_mux_select(codec, adc_idx, - ucontrol->value.enumerated.item[0], false); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0x00); + + /* Find enumerated value for current pinctl setting */ + i = alc_pin_mode_min(dir); + while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl) + i++; + *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir); + return 0; +} + +static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0x00); + + if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir)) + val = alc_pin_mode_min(dir); + + change = pinctl != alc_pin_mode_values[val]; + if (change) { + /* Set pin mode to that requested */ + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + alc_pin_mode_values[val]); + + /* Also enable the retasking pin's input/output as required + * for the requested pin mode. Enum values of 2 or less are + * input modes. + * + * Dynamically switching the input/output buffers probably + * reduces noise slightly (particularly on input) so we'll + * do it. However, having both input and output buffers + * enabled simultaneously doesn't seem to be problematic if + * this turns out to be necessary in the future. + */ + if (val <= 2) { + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, 0); + } else { + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); + } + } + return change; +} + +#define ALC_PIN_MODE(xname, nid, dir) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_pin_mode_info, \ + .get = alc_pin_mode_get, \ + .put = alc_pin_mode_put, \ + .private_value = nid | (dir<<16) } + +/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged + * together using a mask with more than one bit set. This control is + * currently used only by the ALC260 test model. At this stage they are not + * needed for any "production" models. + */ +#ifdef CONFIG_SND_DEBUG +#define alc_gpio_data_info snd_ctl_boolean_mono_info + +static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_GPIO_DATA, 0x00); + + *valp = (val & mask) != 0; + return 0; +} +static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_GPIO_DATA, + 0x00); + + /* Set/unset the masked GPIO bit(s) as needed */ + change = (val == 0 ? 0 : mask) != (gpio_data & mask); + if (val == 0) + gpio_data &= ~mask; + else + gpio_data |= mask; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_GPIO_DATA, gpio_data); + + return change; +} +#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_gpio_data_info, \ + .get = alc_gpio_data_get, \ + .put = alc_gpio_data_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + +/* A switch control to allow the enabling of the digital IO pins on the + * ALC260. This is incredibly simplistic; the intention of this control is + * to provide something in the test model allowing digital outputs to be + * identified if present. If models are found which can utilise these + * outputs a more complete mixer control can be devised for those models if + * necessary. + */ +#ifdef CONFIG_SND_DEBUG +#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info + +static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT_1, 0x00); + + *valp = (val & mask) != 0; + return 0; +} +static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT_1, + 0x00); + + /* Set/unset the masked control bit(s) as needed */ + change = (val == 0 ? 0 : mask) != (ctrl_data & mask); + if (val==0) + ctrl_data &= ~mask; + else + ctrl_data |= mask; + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + ctrl_data); + + return change; +} +#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_spdif_ctrl_info, \ + .get = alc_spdif_ctrl_get, \ + .put = alc_spdif_ctrl_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + +/* A switch control to allow the enabling EAPD digital outputs on the ALC26x. + * Again, this is only used in the ALC26x test models to help identify when + * the EAPD line must be asserted for features to work. + */ +#ifdef CONFIG_SND_DEBUG +#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info + +static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_EAPD_BTLENABLE, 0x00); + + *valp = (val & mask) != 0; + return 0; +} + +static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_EAPD_BTLENABLE, + 0x00); + + /* Set/unset the masked control bit(s) as needed */ + change = (!val ? 0 : mask) != (ctrl_data & mask); + if (!val) + ctrl_data &= ~mask; + else + ctrl_data |= mask; + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, + ctrl_data); + + return change; } +#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_eapd_ctrl_info, \ + .get = alc_eapd_ctrl_get, \ + .put = alc_eapd_ctrl_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + /* * set up the input pin config (depending on the given auto-pin type) */ @@ -354,10 +903,29 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); } +static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (!cfg->line_outs) { + while (cfg->line_outs < AUTO_CFG_MAX_OUTS && + cfg->line_out_pins[cfg->line_outs]) + cfg->line_outs++; + } + if (!cfg->speaker_outs) { + while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS && + cfg->speaker_pins[cfg->speaker_outs]) + cfg->speaker_outs++; + } + if (!cfg->hp_outs) { + while (cfg->hp_outs < AUTO_CFG_MAX_OUTS && + cfg->hp_pins[cfg->hp_outs]) + cfg->hp_outs++; + } +} + /* - * Append the given mixer and verb elements for the later use - * The mixer array is referred in build_controls(), and init_verbs are - * called in init(). */ static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix) { @@ -374,8 +942,61 @@ static void add_verb(struct alc_spec *spec, const struct hda_verb *verb) } /* - * GPIO setup tables, used in initialization + * set up from the preset table */ +static void setup_preset(struct hda_codec *codec, + const struct alc_config_preset *preset) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) + add_mixer(spec, preset->mixers[i]); + spec->cap_mixer = preset->cap_mixer; + for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; + i++) + add_verb(spec, preset->init_verbs[i]); + + spec->channel_mode = preset->channel_mode; + spec->num_channel_mode = preset->num_channel_mode; + spec->need_dac_fix = preset->need_dac_fix; + spec->const_channel_count = preset->const_channel_count; + + if (preset->const_channel_count) + spec->multiout.max_channels = preset->const_channel_count; + else + spec->multiout.max_channels = spec->channel_mode[0].channels; + spec->ext_channel_count = spec->channel_mode[0].channels; + + spec->multiout.num_dacs = preset->num_dacs; + spec->multiout.dac_nids = preset->dac_nids; + spec->multiout.dig_out_nid = preset->dig_out_nid; + spec->multiout.slave_dig_outs = preset->slave_dig_outs; + spec->multiout.hp_nid = preset->hp_nid; + + spec->num_mux_defs = preset->num_mux_defs; + if (!spec->num_mux_defs) + spec->num_mux_defs = 1; + spec->input_mux = preset->input_mux; + + spec->num_adc_nids = preset->num_adc_nids; + spec->adc_nids = preset->adc_nids; + spec->capsrc_nids = preset->capsrc_nids; + spec->dig_in_nid = preset->dig_in_nid; + + spec->unsol_event = preset->unsol_event; + spec->init_hook = preset->init_hook; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->power_hook = preset->power_hook; + spec->loopback.amplist = preset->loopbacks; +#endif + + if (preset->setup) + preset->setup(codec); + + alc_fixup_autocfg_pin_nums(codec); +} + /* Enable GPIO mask and set output */ static const struct hda_verb alc_gpio1_init_verbs[] = { {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, @@ -430,19 +1051,14 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } -/* - * Jack-reporting via input-jack layer - */ - -/* initialization of jacks; currently checks only a few known pins */ static int alc_init_jacks(struct hda_codec *codec) { #ifdef CONFIG_SND_HDA_INPUT_JACK struct alc_spec *spec = codec->spec; int err; unsigned int hp_nid = spec->autocfg.hp_pins[0]; - unsigned int mic_nid = spec->ext_mic_pin; - unsigned int dock_nid = spec->dock_mic_pin; + unsigned int mic_nid = spec->ext_mic.pin; + unsigned int dock_nid = spec->dock_mic.pin; if (hp_nid) { err = snd_hda_input_jack_add(codec, hp_nid, @@ -470,12 +1086,7 @@ static int alc_init_jacks(struct hda_codec *codec) return 0; } -/* - * Jack detections for HP auto-mute and mic-switch - */ - -/* check each pin in the given array; returns true if any of them is plugged */ -static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) +static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) { int i, present = 0; @@ -489,7 +1100,6 @@ static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) return present; } -/* standard HP/line-out auto-mute helper */ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, bool mute, bool hp_out) { @@ -560,7 +1170,6 @@ static void update_speakers(struct hda_codec *codec) spec->autocfg.line_out_pins, on, false); } -/* standard HP-automute helper */ static void alc_hp_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -573,7 +1182,6 @@ static void alc_hp_automute(struct hda_codec *codec) update_speakers(codec); } -/* standard line-out-automute helper */ static void alc_line_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -586,33 +1194,106 @@ static void alc_line_automute(struct hda_codec *codec) update_speakers(codec); } -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 0) +static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t nid) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == nid) + return i; + return -1; +} + +/* switch the current ADC according to the jack state */ +static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int present; + hda_nid_t new_adc; + + present = snd_hda_jack_detect(codec, spec->ext_mic.pin); + if (present) + spec->cur_adc_idx = 1; + else + spec->cur_adc_idx = 0; + new_adc = spec->adc_nids[spec->cur_adc_idx]; + if (spec->cur_adc && spec->cur_adc != new_adc) { + /* stream is running, let's swap the current ADC */ + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); + spec->cur_adc = new_adc; + snd_hda_codec_setup_stream(codec, new_adc, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + } +} -/* standard mic auto-switch helper */ static void alc_mic_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - hda_nid_t *pins = spec->imux_pins; + struct alc_mic_route *dead1, *dead2, *alive; + unsigned int present, type; + hda_nid_t cap_nid; - if (!spec->auto_mic || !spec->auto_mic_valid_imux) + if (!spec->auto_mic) + return; + if (!spec->int_mic.pin || !spec->ext_mic.pin) return; if (snd_BUG_ON(!spec->adc_nids)) return; - if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0)) + + if (spec->dual_adc_switch) { + alc_dual_mic_adc_auto_switch(codec); return; + } - if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx])) - alc_mux_select(codec, 0, spec->ext_mic_idx, false); - else if (spec->dock_mic_idx >= 0 && - snd_hda_jack_detect(codec, pins[spec->dock_mic_idx])) - alc_mux_select(codec, 0, spec->dock_mic_idx, false); - else - alc_mux_select(codec, 0, spec->int_mic_idx, false); + cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; + + alive = &spec->int_mic; + dead1 = &spec->ext_mic; + dead2 = &spec->dock_mic; + + present = snd_hda_jack_detect(codec, spec->ext_mic.pin); + if (present) { + alive = &spec->ext_mic; + dead1 = &spec->int_mic; + dead2 = &spec->dock_mic; + } + if (!present && spec->dock_mic.pin > 0) { + present = snd_hda_jack_detect(codec, spec->dock_mic.pin); + if (present) { + alive = &spec->dock_mic; + dead1 = &spec->int_mic; + dead2 = &spec->ext_mic; + } + snd_hda_input_jack_report(codec, spec->dock_mic.pin); + } + + type = get_wcaps_type(get_wcaps(codec, cap_nid)); + if (type == AC_WID_AUD_MIX) { + /* Matrix-mixer style (e.g. ALC882) */ + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + alive->mux_idx, + HDA_AMP_MUTE, 0); + if (dead1->pin > 0) + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + dead1->mux_idx, + HDA_AMP_MUTE, HDA_AMP_MUTE); + if (dead2->pin > 0) + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + dead2->mux_idx, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* MUX style (e.g. ALC880) */ + snd_hda_codec_write_cache(codec, cap_nid, 0, + AC_VERB_SET_CONNECT_SEL, + alive->mux_idx); + } + snd_hda_input_jack_report(codec, spec->ext_mic.pin); - snd_hda_input_jack_report(codec, pins[spec->ext_mic_idx]); - if (spec->dock_mic_idx >= 0) - snd_hda_input_jack_report(codec, pins[spec->dock_mic_idx]); + /* FIXME: analog mixer */ } /* unsolicited event for HP jack sensing */ @@ -623,19 +1304,18 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) else res >>= 26; switch (res) { - case ALC_HP_EVENT: + case ALC880_HP_EVENT: alc_hp_automute(codec); break; - case ALC_FRONT_EVENT: + case ALC880_FRONT_EVENT: alc_line_automute(codec); break; - case ALC_MIC_EVENT: + case ALC880_MIC_EVENT: alc_mic_automute(codec); break; } } -/* call init functions of standard auto-mute helpers */ static void alc_inithook(struct hda_codec *codec) { alc_hp_automute(codec); @@ -661,7 +1341,6 @@ static void alc888_coef_init(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x3030); } -/* additional initialization for ALC889 variants */ static void alc889_coef_init(struct hda_codec *codec) { unsigned int tmp; @@ -686,12 +1365,28 @@ static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on) static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) { /* We currently only handle front, HP */ - static hda_nid_t pins[] = { - 0x0f, 0x10, 0x14, 0x15, 0 - }; - hda_nid_t *p; - for (p = pins; *p; p++) - set_eapd(codec, *p, on); + switch (codec->vendor_id) { + case 0x10ec0260: + set_eapd(codec, 0x0f, on); + set_eapd(codec, 0x10, on); + break; + case 0x10ec0262: + case 0x10ec0267: + case 0x10ec0268: + case 0x10ec0269: + case 0x10ec0270: + case 0x10ec0272: + case 0x10ec0660: + case 0x10ec0662: + case 0x10ec0663: + case 0x10ec0665: + case 0x10ec0862: + case 0x10ec0889: + case 0x10ec0892: + set_eapd(codec, 0x14, on); + set_eapd(codec, 0x15, on); + break; + } } /* generic shutup callback; @@ -703,12 +1398,10 @@ static void alc_eapd_shutup(struct hda_codec *codec) msleep(200); } -/* generic EAPD initialization */ static void alc_auto_init_amp(struct hda_codec *codec, int type) { unsigned int tmp; - alc_auto_setup_eapd(codec, true); switch (type) { case ALC_INIT_GPIO1: snd_hda_sequence_write(codec, alc_gpio1_init_verbs); @@ -720,6 +1413,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) snd_hda_sequence_write(codec, alc_gpio3_init_verbs); break; case ALC_INIT_DEFAULT: + alc_auto_setup_eapd(codec, true); switch (codec->vendor_id) { case 0x10ec0260: snd_hda_codec_write(codec, 0x1a, 0, @@ -763,9 +1457,6 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) } } -/* - * Auto-Mute mode mixer enum support - */ static int alc_automute_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -852,11 +1543,7 @@ static const struct snd_kcontrol_new alc_automute_mode_enum = { .put = alc_automute_mode_put, }; -static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec) -{ - snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); - return snd_array_new(&spec->kctls); -} +static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec); static int alc_add_automute_mode_enum(struct hda_codec *codec) { @@ -873,10 +1560,6 @@ static int alc_add_automute_mode_enum(struct hda_codec *codec) return 0; } -/* - * Check the availability of HP/line-out auto-mute; - * Set up appropriately if really supported - */ static void alc_init_auto_hp(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -915,7 +1598,7 @@ static void alc_init_auto_hp(struct hda_codec *codec) nid); snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_HP_EVENT); + AC_USRSP_EN | ALC880_HP_EVENT); spec->automute = 1; spec->automute_mode = ALC_AUTOMUTE_PIN; } @@ -930,7 +1613,7 @@ static void alc_init_auto_hp(struct hda_codec *codec) "on NID 0x%x\n", nid); snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_FRONT_EVENT); + AC_USRSP_EN | ALC880_FRONT_EVENT); spec->detect_line = 1; } spec->automute_lines = spec->detect_line; @@ -943,132 +1626,6 @@ static void alc_init_auto_hp(struct hda_codec *codec) } } -/* return the position of NID in the list, or -1 if not found */ -static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return i; - return -1; -} - -/* check whether dynamic ADC-switching is available */ -static bool alc_check_dyn_adc_switch(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, n, idx; - hda_nid_t cap, pin; - - if (imux != spec->input_mux) /* no dynamic imux? */ - return false; - - for (n = 0; n < spec->num_adc_nids; n++) { - cap = spec->private_capsrc_nids[n]; - for (i = 0; i < imux->num_items; i++) { - pin = spec->imux_pins[i]; - if (!pin) - return false; - if (get_connection_index(codec, cap, pin) < 0) - break; - } - if (i >= imux->num_items) - return true; /* no ADC-switch is needed */ - } - - for (i = 0; i < imux->num_items; i++) { - pin = spec->imux_pins[i]; - for (n = 0; n < spec->num_adc_nids; n++) { - cap = spec->private_capsrc_nids[n]; - idx = get_connection_index(codec, cap, pin); - if (idx >= 0) { - imux->items[i].index = idx; - spec->dyn_adc_idx[i] = n; - break; - } - } - } - - snd_printdd("realtek: enabling ADC switching\n"); - spec->dyn_adc_switch = 1; - return true; -} - -/* rebuild imux for matching with the given auto-mic pins (if not yet) */ -static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux; - static char * const texts[3] = { - "Mic", "Internal Mic", "Dock Mic" - }; - int i; - - if (!spec->auto_mic) - return false; - imux = &spec->private_imux[0]; - if (spec->input_mux == imux) - return true; - spec->imux_pins[0] = spec->ext_mic_pin; - spec->imux_pins[1] = spec->int_mic_pin; - spec->imux_pins[2] = spec->dock_mic_pin; - for (i = 0; i < 3; i++) { - strcpy(imux->items[i].label, texts[i]); - if (spec->imux_pins[i]) - imux->num_items = i + 1; - } - spec->num_mux_defs = 1; - spec->input_mux = imux; - return true; -} - -/* check whether all auto-mic pins are valid; setup indices if OK */ -static bool alc_auto_mic_check_imux(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; - - if (!spec->auto_mic) - return false; - if (spec->auto_mic_valid_imux) - return true; /* already checked */ - - /* fill up imux indices */ - if (!alc_check_dyn_adc_switch(codec)) { - spec->auto_mic = 0; - return false; - } - - imux = spec->input_mux; - spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin, - spec->imux_pins, imux->num_items); - spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin, - spec->imux_pins, imux->num_items); - spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin, - spec->imux_pins, imux->num_items); - if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) { - spec->auto_mic = 0; - return false; /* no corresponding imux */ - } - - snd_hda_codec_write_cache(codec, spec->ext_mic_pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_MIC_EVENT); - if (spec->dock_mic_pin) - snd_hda_codec_write_cache(codec, spec->dock_mic_pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_MIC_EVENT); - - spec->auto_mic_valid_imux = 1; - spec->auto_mic = 1; - return true; -} - -/* - * Check the availability of auto-mic switch; - * Set up if really supported - */ static void alc_init_auto_mic(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1076,8 +1633,6 @@ static void alc_init_auto_mic(struct hda_codec *codec) hda_nid_t fixed, ext, dock; int i; - spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1; - fixed = ext = dock = 0; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; @@ -1119,32 +1674,21 @@ static void alc_init_auto_mic(struct hda_codec *codec) return; /* no unsol support */ if (dock && !is_jack_detectable(codec, dock)) return; /* no unsol support */ - - /* check imux indices */ - spec->ext_mic_pin = ext; - spec->int_mic_pin = fixed; - spec->dock_mic_pin = dock; - - spec->auto_mic = 1; - if (!alc_auto_mic_check_imux(codec)) - return; - snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", ext, fixed, dock); + spec->ext_mic.pin = ext; + spec->dock_mic.pin = dock; + spec->int_mic.pin = fixed; + spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ + spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ + spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ + spec->auto_mic = 1; + snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_MIC_EVENT); spec->unsol_event = alc_sku_unsol_event; } -/* check the availabilities of auto-mute and auto-mic switches */ -static void alc_auto_check_switches(struct hda_codec *codec) -{ - alc_init_auto_hp(codec); - alc_init_auto_mic(codec); -} - -/* - * Realtek SSID verification - */ - /* Could be any non-zero and even value. When used as fixup, tells * the driver to ignore any present sku defines. */ @@ -1215,12 +1759,6 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec) return 0; } -/* return true if the given NID is found in the list */ -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - return find_idx_in_nid_list(nid, list, nums) >= 0; -} - /* check subsystem ID and set up device-specific initialization; * return 1 if initialized, 0 if invalid SSID */ @@ -1330,24 +1868,27 @@ static int alc_subsystem_id(struct hda_codec *codec, nid = porti; else return 1; - if (found_in_nid_list(nid, spec->autocfg.line_out_pins, - spec->autocfg.line_outs)) - return 1; + for (i = 0; i < spec->autocfg.line_outs; i++) + if (spec->autocfg.line_out_pins[i] == nid) + return 1; spec->autocfg.hp_pins[0] = nid; } return 1; } -/* Check the validity of ALC subsystem-id - * ports contains an array of 4 pin NIDs for port-A, E, D and I */ -static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) +static void alc_ssid_check(struct hda_codec *codec, + hda_nid_t porta, hda_nid_t porte, + hda_nid_t portd, hda_nid_t porti) { - if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) { + if (!alc_subsystem_id(codec, porta, porte, portd, porti)) { struct alc_spec *spec = codec->spec; snd_printd("realtek: " "Enable default setup for auto mode as fallback\n"); spec->init_amp = ALC_INIT_DEFAULT; } + + alc_init_auto_hp(codec); + alc_init_auto_mic(codec); } /* @@ -1495,9 +2036,6 @@ static void alc_pick_fixup(struct hda_codec *codec, } } -/* - * COEF access helper functions - */ static int alc_read_coef_idx(struct hda_codec *codec, unsigned int coef_idx) { @@ -1518,32 +2056,20 @@ static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx, coef_val); } -/* - * Digital I/O handling - */ - /* set right pin controls for digital I/O */ static void alc_auto_init_digital(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int i; - hda_nid_t pin, dac; + hda_nid_t pin; for (i = 0; i < spec->autocfg.dig_outs; i++) { pin = spec->autocfg.dig_out_pins[i]; - if (!pin) - continue; - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - if (!i) - dac = spec->multiout.dig_out_nid; - else - dac = spec->slave_dig_outs[i - 1]; - if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP)) - continue; - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); + if (pin) { + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + } } pin = spec->autocfg.dig_in_pin; if (pin) @@ -1561,13 +2087,11 @@ static void alc_auto_parse_digital(struct hda_codec *codec) /* support multiple SPDIFs; the secondary is set up as a slave */ for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t conn[4]; err = snd_hda_get_connections(codec, spec->autocfg.dig_out_pins[i], - conn, ARRAY_SIZE(conn)); + &dig_nid, 1); if (err < 0) continue; - dig_nid = conn[0]; /* assume the first element is audio-out */ if (!i) { spec->multiout.dig_out_nid = dig_nid; spec->dig_out_type = spec->autocfg.dig_out_type[0]; @@ -1600,1790 +2124,13960 @@ static void alc_auto_parse_digital(struct hda_codec *codec) } /* - * capture mixer elements + * ALC888 */ -static int alc_cap_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long val; - int err; - mutex_lock(&codec->control_mutex); - if (spec->vol_in_capsrc) - val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); - kcontrol->private_value = val; - err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); - mutex_unlock(&codec->control_mutex); - return err; -} +/* + * 2ch mode + */ +static const struct hda_verb alc888_4ST_ch2_intel_init[] = { +/* Mic-in jack as mic in */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-in jack as Line in */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-Out as Front */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } /* end */ +}; -static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *tlv) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long val; - int err; +/* + * 4ch mode + */ +static const struct hda_verb alc888_4ST_ch4_intel_init[] = { +/* Mic-in jack as mic in */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as Front */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } /* end */ +}; - mutex_lock(&codec->control_mutex); - if (spec->vol_in_capsrc) - val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); - kcontrol->private_value = val; - err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); - mutex_unlock(&codec->control_mutex); - return err; -} +/* + * 6ch mode + */ +static const struct hda_verb alc888_4ST_ch6_intel_init[] = { +/* Mic-in jack as CLFE */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + { } /* end */ +}; -typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); +/* + * 8ch mode + */ +static const struct hda_verb alc888_4ST_ch8_intel_init[] = { +/* Mic-in jack as CLFE */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as Side */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + { } /* end */ +}; -static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol, - getput_call_t func, bool check_adc_switch) +static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { + { 2, alc888_4ST_ch2_intel_init }, + { 4, alc888_4ST_ch4_intel_init }, + { 6, alc888_4ST_ch6_intel_init }, + { 8, alc888_4ST_ch8_intel_init }, +}; + +/* + * ALC888 Fujitsu Siemens Amillo xa3530 + */ + +static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Connect Internal HP to Front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Bass HP to Front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Line-Out side jack (SPDIF) to Side */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, +/* Connect Mic jack to CLFE */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, +/* Connect Line-in jack to Surround */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, +/* Connect HP out jack to Front */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Enable unsolicited event for HP jack and Line-out jack */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {} +}; + +static void alc889_automute_setup(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - int i, err = 0; - mutex_lock(&codec->control_mutex); - if (check_adc_switch && spec->dyn_adc_switch) { - for (i = 0; i < spec->num_adc_nids; i++) { - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], - 3, 0, HDA_INPUT); - err = func(kcontrol, ucontrol); - if (err < 0) - goto error; - } - } else { - i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - if (spec->vol_in_capsrc) - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i], - 3, 0, HDA_OUTPUT); - else - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], - 3, 0, HDA_INPUT); - err = func(kcontrol, ucontrol); - } - error: - mutex_unlock(&codec->control_mutex); - return err; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; + spec->autocfg.speaker_pins[3] = 0x19; + spec->autocfg.speaker_pins[4] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static int alc_cap_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc889_intel_init_hook(struct hda_codec *codec) { - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_get, false); + alc889_coef_init(codec); + alc_hp_automute(codec); } -static int alc_cap_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) { - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_put, true); + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x17; /* line-out */ + spec->autocfg.hp_pins[1] = 0x1b; /* hp */ + spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ + spec->autocfg.speaker_pins[1] = 0x15; /* bass */ + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -/* capture mixer elements */ -#define alc_cap_sw_info snd_ctl_boolean_stereo_info +/* + * ALC888 Acer Aspire 4930G model + */ -static int alc_cap_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_get, false); -} +static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Connect Internal HP to front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect HP out to front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; -static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_put, true); -} +/* + * ALC888 Acer Aspire 6530G model + */ -#define _DEFINE_CAPMIX(num) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Capture Switch", \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .count = num, \ - .info = alc_cap_sw_info, \ - .get = alc_cap_sw_get, \ - .put = alc_cap_sw_put, \ - }, \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Capture Volume", \ - .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \ - .count = num, \ - .info = alc_cap_vol_info, \ - .get = alc_cap_vol_get, \ - .put = alc_cap_vol_put, \ - .tlv = { .c = alc_cap_vol_tlv }, \ - } +static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = { +/* Route to built-in subwoofer as well as speakers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +/* Bias voltage on for external mic port */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Enable speaker output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, +/* Enable headphone output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; -#define _DEFINE_CAPSRC(num) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - /* .name = "Capture Source", */ \ - .name = "Input Source", \ - .count = num, \ - .info = alc_mux_enum_info, \ - .get = alc_mux_enum_get, \ - .put = alc_mux_enum_put, \ - } +/* + *ALC888 Acer Aspire 7730G model + */ -#define DEFINE_CAPMIX(num) \ -static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ - _DEFINE_CAPMIX(num), \ - _DEFINE_CAPSRC(num), \ - { } /* end */ \ -} - -#define DEFINE_CAPMIX_NOSRC(num) \ -static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ - _DEFINE_CAPMIX(num), \ - { } /* end */ \ -} - -/* up to three ADCs */ -DEFINE_CAPMIX(1); -DEFINE_CAPMIX(2); -DEFINE_CAPMIX(3); -DEFINE_CAPMIX_NOSRC(1); -DEFINE_CAPMIX_NOSRC(2); -DEFINE_CAPMIX_NOSRC(3); +static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = { +/* Bias voltage on for external mic port */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Enable speaker output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, +/* Enable headphone output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, +/*Enable internal subwoofer */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; /* - * virtual master controls + * ALC889 Acer Aspire 8930G model */ -/* - * slave controls for virtual master +static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Connect Internal Front to Front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Internal Rear to Rear */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, +/* Connect Internal CLFE to CLFE */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, +/* Connect HP out to Front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Enable all DACs */ +/* DAC DISABLE/MUTE 1? */ +/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x03}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, +/* DAC DISABLE/MUTE 2? */ +/* some bit here disables the other DACs. Init=0x4900 */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x08}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, +/* DMIC fix + * This laptop has a stereo digital microphone. The mics are only 1cm apart + * which makes the stereo useless. However, either the mic or the ALC889 + * makes the signal become a difference/sum signal instead of standard + * stereo, which is annoying. So instead we flip this bit which makes the + * codec replicate the sum signal to both channels, turning it into a + * normal mono mic. */ -static const char * const alc_slave_vols[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - "Side Playback Volume", - "Headphone Playback Volume", - "Speaker Playback Volume", - "Mono Playback Volume", - "Line-Out Playback Volume", - NULL, +/* DMIC_CONTROL? Init value = 0x0001 */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0003}, + { } }; -static const char * const alc_slave_sws[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - "Side Playback Switch", - "Headphone Playback Switch", - "Speaker Playback Switch", - "Mono Playback Switch", - "IEC958 Playback Switch", - "Line-Out Playback Switch", - NULL, +static const struct hda_input_mux alc888_2_capture_sources[2] = { + /* Front mic only available on one ADC */ + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Front Mic", 0xb }, + }, + }, + { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, + } }; -/* - * build control elements - */ +static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { + /* Interal mic only available on one ADC */ + { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Line In", 0x2 }, + { "CD", 0x4 }, + { "Input Mix", 0xa }, + { "Internal Mic", 0xb }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line In", 0x2 }, + { "CD", 0x4 }, + { "Input Mix", 0xa }, + }, + } +}; -#define NID_MAPPING (-1) +static const struct hda_input_mux alc889_capture_sources[3] = { + /* Digital mic only available on first "ADC" */ + { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Front Mic", 0xb }, + { "Input Mix", 0xa }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Input Mix", 0xa }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Input Mix", 0xa }, + }, + } +}; -#define SUBDEV_SPEAKER_ (0 << 6) -#define SUBDEV_HP_ (1 << 6) -#define SUBDEV_LINE_ (2 << 6) -#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f)) -#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f)) -#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f)) +static const struct snd_kcontrol_new alc888_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; -static void alc_free_kctls(struct hda_codec *codec); +static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; -#ifdef CONFIG_SND_HDA_INPUT_BEEP -/* additional beep mixers; the actual parameters are overwritten at build */ -static const struct snd_kcontrol_new alc_beep_mixer[] = { - HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), - HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), +static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; -#endif -static int alc_build_controls(struct hda_codec *codec) + +static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - struct snd_kcontrol *kctl = NULL; - const struct snd_kcontrol_new *knew; - int i, j, err; - unsigned int u; - hda_nid_t nid; - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (spec->cap_mixer) { - err = snd_hda_add_new_ctls(codec, spec->cap_mixer); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - if (!spec->no_analog) { - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} -#ifdef CONFIG_SND_HDA_INPUT_BEEP - /* create beep controls if needed */ - if (spec->beep_amp) { - const struct snd_kcontrol_new *knew; - for (knew = alc_beep_mixer; knew->name; knew++) { - struct snd_kcontrol *kctl; - kctl = snd_ctl_new1(knew, codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - } - } -#endif +static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; - /* if we have no master control, let's create it */ - if (!spec->no_analog && - !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, - HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, alc_slave_vols); - if (err < 0) - return err; - } - if (!spec->no_analog && - !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, alc_slave_sws); - if (err < 0) - return err; - } + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} - /* assign Capture Source enums to NID */ - if (spec->capsrc_nids || spec->adc_nids) { - kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); - if (!kctl) - kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); - for (i = 0; kctl && i < kctl->count; i++) { - const hda_nid_t *nids = spec->capsrc_nids; - if (!nids) - nids = spec->adc_nids; - err = snd_hda_add_nid(codec, kctl, i, nids[i]); - if (err < 0) - return err; - } - } - if (spec->cap_mixer) { - const char *kname = kctl ? kctl->id.name : NULL; - for (knew = spec->cap_mixer; knew->name; knew++) { - if (kname && strcmp(knew->name, kname) == 0) - continue; - kctl = snd_hda_find_mixer_ctl(codec, knew->name); - for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nid(codec, kctl, i, - spec->adc_nids[i]); - if (err < 0) - return err; - } - } - } +static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; - /* other nid->control mapping */ - for (i = 0; i < spec->num_mixers; i++) { - for (knew = spec->mixers[i]; knew->name; knew++) { - if (knew->iface != NID_MAPPING) - continue; - kctl = snd_hda_find_mixer_ctl(codec, knew->name); - if (kctl == NULL) - continue; - u = knew->subdevice; - for (j = 0; j < 4; j++, u >>= 8) { - nid = u & 0x3f; - if (nid == 0) - continue; - switch (u & 0xc0) { - case SUBDEV_SPEAKER_: - nid = spec->autocfg.speaker_pins[nid]; - break; - case SUBDEV_LINE_: - nid = spec->autocfg.line_out_pins[nid]; - break; - case SUBDEV_HP_: - nid = spec->autocfg.hp_pins[nid]; - break; - default: - continue; - } - err = snd_hda_add_nid(codec, kctl, 0, nid); - if (err < 0) - return err; - } - u = knew->private_value; - for (j = 0; j < 4; j++, u >>= 8) { - nid = u & 0xff; - if (nid == 0) - continue; - err = snd_hda_add_nid(codec, kctl, 0, nid); - if (err < 0) - return err; - } - } - } + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} - alc_free_kctls(codec); /* no longer needed */ +static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; - return 0; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } - /* - * Common callbacks + * ALC880 3-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) + * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, + * F-Mic = 0x1b, HP = 0x19 */ -static void alc_init_special_input_src(struct hda_codec *codec); +static const hda_nid_t alc880_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x05, 0x04, 0x03 +}; -static int alc_init(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - unsigned int i; +static const hda_nid_t alc880_adc_nids[3] = { + /* ADC0-2 */ + 0x07, 0x08, 0x09, +}; - alc_fix_pll(codec); - alc_auto_init_amp(codec, spec->init_amp); +/* The datasheet says the node 0x07 is connected from inputs, + * but it shows zero connection in the real implementation on some devices. + * Note: this is a 915GAV bug, fixed on 915GLV + */ +static const hda_nid_t alc880_adc_nids_alt[2] = { + /* ADC1-2 */ + 0x08, 0x09, +}; - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - alc_init_special_input_src(codec); +#define ALC880_DIGOUT_NID 0x06 +#define ALC880_DIGIN_NID 0x0a - if (spec->init_hook) - spec->init_hook(codec); +static const struct hda_input_mux alc880_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x3 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; - alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); +/* channel source setting (2/6 channel selection for 3-stack) */ +/* 2ch mode */ +static const struct hda_verb alc880_threestack_ch2_init[] = { + /* set line-in to input, mute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + /* set mic-in to input vref 80%, mute it */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; - hda_call_check_power_status(codec, 0x01); - return 0; -} +/* 6ch mode */ +static const struct hda_verb alc880_threestack_ch6_init[] = { + /* set line-in to output, unmute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + /* set mic-in to output, unmute it */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ +}; -static void alc_unsol_event(struct hda_codec *codec, unsigned int res) -{ - struct alc_spec *spec = codec->spec; +static const struct hda_channel_mode alc880_threestack_modes[2] = { + { 2, alc880_threestack_ch2_init }, + { 6, alc880_threestack_ch6_init }, +}; - if (spec->unsol_event) - spec->unsol_event(codec, res); -} +static const struct snd_kcontrol_new alc880_three_stack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; -#ifdef CONFIG_SND_HDA_POWER_SAVE -static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) +/* capture mixer elements */ +static int alc_cap_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); -} -#endif + int err; -/* - * Analog playback callbacks - */ -static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); + mutex_lock(&codec->control_mutex); + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, + HDA_INPUT); + err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + mutex_unlock(&codec->control_mutex); + return err; } -static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) +static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} + int err; -static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); + mutex_lock(&codec->control_mutex); + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, + HDA_INPUT); + err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); + mutex_unlock(&codec->control_mutex); + return err; } -/* - * Digital out - */ -static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, + getput_call_t func, bool check_adc_switch) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); + int i, err = 0; + + mutex_lock(&codec->control_mutex); + if (check_adc_switch && spec->dual_adc_switch) { + for (i = 0; i < spec->num_adc_nids; i++) { + kcontrol->private_value = + HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], + 3, 0, HDA_INPUT); + err = func(kcontrol, ucontrol); + if (err < 0) + goto error; + } + } else { + i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + kcontrol->private_value = + HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], + 3, 0, HDA_INPUT); + err = func(kcontrol, ucontrol); + } + error: + mutex_unlock(&codec->control_mutex); + return err; } -static int alc_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) +static int alc_cap_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_volume_get, false); } -static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +static int alc_cap_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_volume_put, true); } -static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +/* capture mixer elements */ +#define alc_cap_sw_info snd_ctl_boolean_stereo_info + +static int alc_cap_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_switch_get, false); } -/* - * Analog capture - */ -static int alc_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) +static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct alc_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], - stream_tag, 0, format); - return 0; + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_switch_put, true); } -static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; +#define _DEFINE_CAPMIX(num) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Capture Switch", \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .count = num, \ + .info = alc_cap_sw_info, \ + .get = alc_cap_sw_get, \ + .put = alc_cap_sw_put, \ + }, \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Capture Volume", \ + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \ + .count = num, \ + .info = alc_cap_vol_info, \ + .get = alc_cap_vol_get, \ + .put = alc_cap_vol_put, \ + .tlv = { .c = alc_cap_vol_tlv }, \ + } - snd_hda_codec_cleanup_stream(codec, - spec->adc_nids[substream->number + 1]); - return 0; -} +#define _DEFINE_CAPSRC(num) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + /* .name = "Capture Source", */ \ + .name = "Input Source", \ + .count = num, \ + .info = alc_mux_enum_info, \ + .get = alc_mux_enum_get, \ + .put = alc_mux_enum_put, \ + } -/* analog capture with dynamic dual-adc changes */ -static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - return 0; +#define DEFINE_CAPMIX(num) \ +static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ + _DEFINE_CAPMIX(num), \ + _DEFINE_CAPSRC(num), \ + { } /* end */ \ } -static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; +#define DEFINE_CAPMIX_NOSRC(num) \ +static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ + _DEFINE_CAPMIX(num), \ + { } /* end */ \ } -static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = dyn_adc_capture_pcm_prepare, - .cleanup = dyn_adc_capture_pcm_cleanup - }, -}; +/* up to three ADCs */ +DEFINE_CAPMIX(1); +DEFINE_CAPMIX(2); +DEFINE_CAPMIX(3); +DEFINE_CAPMIX_NOSRC(1); +DEFINE_CAPMIX_NOSRC(2); +DEFINE_CAPMIX_NOSRC(3); /* + * ALC880 5-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), + * Side = 0x02 (0xd) + * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 + * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 */ -static const struct hda_pcm_stream alc_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc_playback_pcm_open, - .prepare = alc_playback_pcm_prepare, - .cleanup = alc_playback_pcm_cleanup - }, + +/* additional mixers to alc880_three_stack_mixer */ +static const struct snd_kcontrol_new alc880_five_stack_mixer[] = { + HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), + { } /* end */ }; -static const struct hda_pcm_stream alc_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ +/* channel source setting (6/8 channel selection for 5-stack) */ +/* 6ch mode */ +static const struct hda_verb alc880_fivestack_ch6_init[] = { + /* set line-in to input, mute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ }; -static const struct hda_pcm_stream alc_pcm_analog_alt_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ +/* 8ch mode */ +static const struct hda_verb alc880_fivestack_ch8_init[] = { + /* set line-in to output, unmute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ }; -static const struct hda_pcm_stream alc_pcm_analog_alt_capture = { - .substreams = 2, /* can be overridden */ - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .prepare = alc_alt_capture_pcm_prepare, - .cleanup = alc_alt_capture_pcm_cleanup - }, +static const struct hda_channel_mode alc880_fivestack_modes[2] = { + { 6, alc880_fivestack_ch6_init }, + { 8, alc880_fivestack_ch8_init }, }; -static const struct hda_pcm_stream alc_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc_dig_playback_pcm_open, - .close = alc_dig_playback_pcm_close, - .prepare = alc_dig_playback_pcm_prepare, - .cleanup = alc_dig_playback_pcm_cleanup + +/* + * ALC880 6-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), + * Side = 0x05 (0x0f) + * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, + * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b + */ + +static const hda_nid_t alc880_6st_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x03, 0x04, 0x05 +}; + +static const struct hda_input_mux alc880_6stack_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, }, }; -static const struct hda_pcm_stream alc_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ +/* fixed 8-channels */ +static const struct hda_channel_mode alc880_sixstack_modes[1] = { + { 8, NULL }, }; -/* Used by alc_build_pcms to flag that a PCM has no playback stream */ -static const struct hda_pcm_stream alc_pcm_null_stream = { - .substreams = 0, - .channels_min = 0, - .channels_max = 0, +static const struct snd_kcontrol_new alc880_six_stack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ }; -static int alc_build_pcms(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - const struct hda_pcm_stream *p; - int i; - codec->num_pcms = 1; - codec->pcm_info = info; +/* + * ALC880 W810 model + * + * W810 has rear IO for: + * Front (DAC 02) + * Surround (DAC 03) + * Center/LFE (DAC 04) + * Digital out (06) + * + * The system also has a pair of internal speakers, and a headphone jack. + * These are both connected to Line2 on the codec, hence to DAC 02. + * + * There is a variable resistor to control the speaker or headphone + * volume. This is a hardware-only device without a software API. + * + * Plugging headphones in will disable the internal speakers. This is + * implemented in hardware, not via the driver using jack sense. In + * a similar fashion, plugging into the rear socket marked "front" will + * disable both the speakers and headphones. + * + * For input, there's a microphone jack, and an "audio in" jack. + * These may not do anything useful with this driver yet, because I + * haven't setup any initialization verbs for these yet... + */ - if (spec->no_analog) - goto skip_analog; +static const hda_nid_t alc880_w810_dac_nids[3] = { + /* front, rear/surround, clfe */ + 0x02, 0x03, 0x04 +}; - snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); - info->name = spec->stream_name_analog; +/* fixed 6 channels */ +static const struct hda_channel_mode alc880_w810_modes[1] = { + { 6, NULL } +}; - if (spec->multiout.dac_nids > 0) { - p = spec->stream_analog_playback; - if (!p) - p = &alc_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - } - if (spec->adc_nids) { - p = spec->stream_analog_capture; - if (!p) { - if (spec->dyn_adc_switch) - p = &dyn_adc_pcm_analog_capture; - else - p = &alc_pcm_analog_capture; - } - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - } +/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ +static const struct snd_kcontrol_new alc880_w810_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + { } /* end */ +}; - if (spec->channel_mode) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; - for (i = 0; i < spec->num_channel_mode; i++) { - if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; - } - } - } - skip_analog: - /* SPDIF for stream index #1 */ - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - snprintf(spec->stream_name_digital, - sizeof(spec->stream_name_digital), - "%s Digital", codec->chip_name); - codec->num_pcms = 2; - codec->slave_dig_outs = spec->multiout.slave_dig_outs; - info = spec->pcm_rec + 1; - info->name = spec->stream_name_digital; - if (spec->dig_out_type) - info->pcm_type = spec->dig_out_type; - else - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - p = spec->stream_digital_playback; - if (!p) - p = &alc_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - p = spec->stream_digital_capture; - if (!p) - p = &alc_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - /* FIXME: do we need this for all Realtek codec models? */ - codec->spdif_status_reset = 1; - } +/* + * Z710V model + * + * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) + * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), + * Line = 0x1a + */ - if (spec->no_analog) - return 0; +static const hda_nid_t alc880_z71v_dac_nids[1] = { + 0x02 +}; +#define ALC880_Z71V_HP_DAC 0x03 - /* If the use of more than one ADC is requested for the current - * model, configure a second analog capture-only PCM. - */ - /* Additional Analaog capture for index #2 */ - if (spec->alt_dac_nid || spec->num_adc_nids > 1) { - codec->num_pcms = 3; - info = spec->pcm_rec + 2; - info->name = spec->stream_name_analog; - if (spec->alt_dac_nid) { - p = spec->stream_analog_alt_playback; - if (!p) - p = &alc_pcm_analog_alt_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->alt_dac_nid; - } else { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - alc_pcm_null_stream; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; - } - if (spec->num_adc_nids > 1) { - p = spec->stream_analog_alt_capture; - if (!p) - p = &alc_pcm_analog_alt_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->adc_nids[1]; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids - 1; - } else { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - alc_pcm_null_stream; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; - } - } +/* fixed 2 channels */ +static const struct hda_channel_mode alc880_2_jack_modes[1] = { + { 2, NULL } +}; - return 0; -} +static const struct snd_kcontrol_new alc880_z71v_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; -static inline void alc_shutup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (spec && spec->shutup) - spec->shutup(codec); - snd_hda_shutup_pins(codec); -} +/* + * ALC880 F1734 model + * + * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) + * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 + */ -static void alc_free_kctls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; +static const hda_nid_t alc880_f1734_dac_nids[1] = { + 0x03 +}; +#define ALC880_F1734_HP_DAC 0x02 + +static const struct snd_kcontrol_new alc880_f1734_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} +static const struct hda_input_mux alc880_f1734_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "CD", 0x4 }, + }, +}; -static void alc_free(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (!spec) - return; +/* + * ALC880 ASUS model + * + * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) + * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, + * Mic = 0x18, Line = 0x1a + */ - alc_shutup(codec); - snd_hda_input_jack_free(codec); - alc_free_kctls(codec); - kfree(spec); - snd_hda_detach_beep_device(codec); -} +#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ +#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ + +static const struct snd_kcontrol_new alc880_asus_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; -#ifdef CONFIG_SND_HDA_POWER_SAVE -static void alc_power_eapd(struct hda_codec *codec) -{ - alc_auto_setup_eapd(codec, false); -} +/* + * ALC880 ASUS W1V model + * + * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) + * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, + * Mic = 0x18, Line = 0x1a, Line2 = 0x1b + */ -static int alc_suspend(struct hda_codec *codec, pm_message_t state) -{ - struct alc_spec *spec = codec->spec; - alc_shutup(codec); - if (spec && spec->power_hook) - spec->power_hook(codec); - return 0; -} -#endif +/* additional mixers to alc880_asus_mixer */ +static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { + HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), + { } /* end */ +}; -#ifdef SND_HDA_NEEDS_RESUME -static int alc_resume(struct hda_codec *codec) -{ - msleep(150); /* to avoid pop noise */ - codec->patch_ops.init(codec); - snd_hda_codec_resume_amp(codec); - snd_hda_codec_resume_cache(codec); - hda_call_check_power_status(codec, 0x01); - return 0; -} -#endif +/* TCL S700 */ +static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { } /* end */ +}; -/* - */ -static const struct hda_codec_ops alc_patch_ops = { - .build_controls = alc_build_controls, - .build_pcms = alc_build_pcms, - .init = alc_init, - .free = alc_free, - .unsol_event = alc_unsol_event, -#ifdef SND_HDA_NEEDS_RESUME - .resume = alc_resume, -#endif -#ifdef CONFIG_SND_HDA_POWER_SAVE - .suspend = alc_suspend, - .check_power_status = alc_check_power_status, -#endif - .reboot_notify = alc_shutup, +/* Uniwill */ +static const struct snd_kcontrol_new alc880_uniwill_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ }; -/* replace the codec chip_name with the given string */ -static int alc_codec_rename(struct hda_codec *codec, const char *name) -{ - kfree(codec->chip_name); - codec->chip_name = kstrdup(name, GFP_KERNEL); - if (!codec->chip_name) { - alc_free(codec); - return -ENOMEM; - } - return 0; -} +static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; /* - * Automatic parse of I/O pins from the BIOS configuration + * virtual master controls */ -enum { - ALC_CTL_WIDGET_VOL, - ALC_CTL_WIDGET_MUTE, - ALC_CTL_BIND_MUTE, -}; -static const struct snd_kcontrol_new alc_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - HDA_BIND_MUTE(NULL, 0, 0, 0), +/* + * slave controls for virtual master + */ +static const char * const alc_slave_vols[] = { + "Front Playback Volume", + "Surround Playback Volume", + "Center Playback Volume", + "LFE Playback Volume", + "Side Playback Volume", + "Headphone Playback Volume", + "Speaker Playback Volume", + "Mono Playback Volume", + "Line-Out Playback Volume", + NULL, }; -/* add dynamic controls */ -static int add_control(struct alc_spec *spec, int type, const char *name, - int cidx, unsigned long val) -{ - struct snd_kcontrol_new *knew; - - knew = alc_kcontrol_new(spec); +static const char * const alc_slave_sws[] = { + "Front Playback Switch", + "Surround Playback Switch", + "Center Playback Switch", + "LFE Playback Switch", + "Side Playback Switch", + "Headphone Playback Switch", + "Speaker Playback Switch", + "Mono Playback Switch", + "IEC958 Playback Switch", + "Line-Out Playback Switch", + NULL, +}; + +/* + * build control elements + */ + +#define NID_MAPPING (-1) + +#define SUBDEV_SPEAKER_ (0 << 6) +#define SUBDEV_HP_ (1 << 6) +#define SUBDEV_LINE_ (2 << 6) +#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f)) +#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f)) +#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f)) + +static void alc_free_kctls(struct hda_codec *codec); + +#ifdef CONFIG_SND_HDA_INPUT_BEEP +/* additional beep mixers; the actual parameters are overwritten at build */ +static const struct snd_kcontrol_new alc_beep_mixer[] = { + HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), + HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), + { } /* end */ +}; +#endif + +static int alc_build_controls(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct snd_kcontrol *kctl = NULL; + const struct snd_kcontrol_new *knew; + int i, j, err; + unsigned int u; + hda_nid_t nid; + + for (i = 0; i < spec->num_mixers; i++) { + err = snd_hda_add_new_ctls(codec, spec->mixers[i]); + if (err < 0) + return err; + } + if (spec->cap_mixer) { + err = snd_hda_add_new_ctls(codec, spec->cap_mixer); + if (err < 0) + return err; + } + if (spec->multiout.dig_out_nid) { + err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid); + if (err < 0) + return err; + if (!spec->no_analog) { + err = snd_hda_create_spdif_share_sw(codec, + &spec->multiout); + if (err < 0) + return err; + spec->multiout.share_spdif = 1; + } + } + if (spec->dig_in_nid) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); + if (err < 0) + return err; + } + +#ifdef CONFIG_SND_HDA_INPUT_BEEP + /* create beep controls if needed */ + if (spec->beep_amp) { + const struct snd_kcontrol_new *knew; + for (knew = alc_beep_mixer; knew->name; knew++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); + if (err < 0) + return err; + } + } +#endif + + /* if we have no master control, let's create it */ + if (!spec->no_analog && + !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { + unsigned int vmaster_tlv[4]; + snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, + HDA_OUTPUT, vmaster_tlv); + err = snd_hda_add_vmaster(codec, "Master Playback Volume", + vmaster_tlv, alc_slave_vols); + if (err < 0) + return err; + } + if (!spec->no_analog && + !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { + err = snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, alc_slave_sws); + if (err < 0) + return err; + } + + /* assign Capture Source enums to NID */ + if (spec->capsrc_nids || spec->adc_nids) { + kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); + if (!kctl) + kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); + for (i = 0; kctl && i < kctl->count; i++) { + const hda_nid_t *nids = spec->capsrc_nids; + if (!nids) + nids = spec->adc_nids; + err = snd_hda_add_nid(codec, kctl, i, nids[i]); + if (err < 0) + return err; + } + } + if (spec->cap_mixer) { + const char *kname = kctl ? kctl->id.name : NULL; + for (knew = spec->cap_mixer; knew->name; knew++) { + if (kname && strcmp(knew->name, kname) == 0) + continue; + kctl = snd_hda_find_mixer_ctl(codec, knew->name); + for (i = 0; kctl && i < kctl->count; i++) { + err = snd_hda_add_nid(codec, kctl, i, + spec->adc_nids[i]); + if (err < 0) + return err; + } + } + } + + /* other nid->control mapping */ + for (i = 0; i < spec->num_mixers; i++) { + for (knew = spec->mixers[i]; knew->name; knew++) { + if (knew->iface != NID_MAPPING) + continue; + kctl = snd_hda_find_mixer_ctl(codec, knew->name); + if (kctl == NULL) + continue; + u = knew->subdevice; + for (j = 0; j < 4; j++, u >>= 8) { + nid = u & 0x3f; + if (nid == 0) + continue; + switch (u & 0xc0) { + case SUBDEV_SPEAKER_: + nid = spec->autocfg.speaker_pins[nid]; + break; + case SUBDEV_LINE_: + nid = spec->autocfg.line_out_pins[nid]; + break; + case SUBDEV_HP_: + nid = spec->autocfg.hp_pins[nid]; + break; + default: + continue; + } + err = snd_hda_add_nid(codec, kctl, 0, nid); + if (err < 0) + return err; + } + u = knew->private_value; + for (j = 0; j < 4; j++, u >>= 8) { + nid = u & 0xff; + if (nid == 0) + continue; + err = snd_hda_add_nid(codec, kctl, 0, nid); + if (err < 0) + return err; + } + } + } + + alc_free_kctls(codec); /* no longer needed */ + + return 0; +} + + +/* + * initialize the codec volumes, etc + */ + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc880_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for front + * panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + + /* + * Set up output mixers (0x0c - 0x0f) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +/* + * 3-stack pin configuration: + * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b + */ +static const struct hda_verb alc880_pin_3stack_init_verbs[] = { + /* + * preset connection lists of input pins + * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround + */ + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ + + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line2 (as front mic) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * 5-stack pin configuration: + * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, + * line-in/side = 0x1a, f-mic = 0x1b + */ +static const struct hda_verb alc880_pin_5stack_init_verbs[] = { + /* + * preset connection lists of input pins + * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround + */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ + + /* + * Set pin mode and muting + */ + /* set pin widgets 0x14-0x17 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* unmute pins for output (no gain on this amp) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line2 (as front mic) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * W810 pin configuration: + * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b + */ +static const struct hda_verb alc880_pin_w810_init_verbs[] = { + /* hphone/speaker input selector: front DAC */ + {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + { } +}; + +/* + * Z71V pin configuration: + * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) + */ +static const struct hda_verb alc880_pin_z71v_init_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * 6-stack pin configuration: + * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, + * f-mic = 0x19, line = 0x1a, HP = 0x1b + */ +static const struct hda_verb alc880_pin_6stack_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * Uniwill pin configuration: + * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, + * line = 0x1a + */ +static const struct hda_verb alc880_uniwill_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */ + /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + + { } +}; + +/* +* Uniwill P53 +* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, + */ +static const struct hda_verb alc880_uniwill_p53_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT}, + + { } +}; + +static const struct hda_verb alc880_beep_init_verbs[] = { + { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, + { } +}; + +/* auto-toggle front mic */ +static void alc88x_simple_mic_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_jack_detect(codec, 0x18); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); +} + +static void alc880_uniwill_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc880_uniwill_init_hook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc88x_simple_mic_automute(codec); +} + +static void alc880_uniwill_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + switch (res >> 28) { + case ALC880_MIC_EVENT: + alc88x_simple_mic_automute(codec); + break; + default: + alc_sku_unsol_event(codec, res); + break; + } +} + +static void alc880_uniwill_p53_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x21, 0, + AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); + present &= HDA_AMP_VOLMASK; + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); + snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); +} + +static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == ALC880_DCVOL_EVENT) + alc880_uniwill_p53_dcvol_automute(codec); + else + alc_sku_unsol_event(codec, res); +} + +/* + * F1734 pin configuration: + * HP = 0x14, speaker-out = 0x15, mic = 0x18 + */ +static const struct hda_verb alc880_pin_f1734_init_verbs[] = { + {0x07, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT}, + + { } +}; + +/* + * ASUS pin configuration: + * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a + */ +static const struct hda_verb alc880_pin_asus_init_verbs[] = { + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* Enable GPIO mask and set output */ +#define alc880_gpio1_init_verbs alc_gpio1_init_verbs +#define alc880_gpio2_init_verbs alc_gpio2_init_verbs +#define alc880_gpio3_init_verbs alc_gpio3_init_verbs + +/* Clevo m520g init */ +static const struct hda_verb alc880_pin_clevo_init_verbs[] = { + /* headphone output */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* line-out */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line-in */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* CD */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic1 (rear panel) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic2 (front panel) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* headphone */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + + { } +}; + +static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + + /* Headphone output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Front output*/ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, + + { } +}; + +/* + * LG m1 express dual + * + * Pin assignment: + * Rear Line-In/Out (blue): 0x14 + * Build-in Mic-In: 0x15 + * Speaker-out: 0x17 + * HP-Out (green): 0x1b + * Mic-In/Out (red): 0x19 + * SPDIF-Out: 0x1e + */ + +/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */ +static const hda_nid_t alc880_lg_dac_nids[3] = { + 0x05, 0x02, 0x03 +}; + +/* seems analog CD is not working */ +static const struct hda_input_mux alc880_lg_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x1 }, + { "Line", 0x5 }, + { "Internal Mic", 0x6 }, + }, +}; + +/* 2,4,6 channel modes */ +static const struct hda_verb alc880_lg_ch2_init[] = { + /* set line-in and mic-in to input */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { } +}; + +static const struct hda_verb alc880_lg_ch4_init[] = { + /* set line-in to out and mic-in to input */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { } +}; + +static const struct hda_verb alc880_lg_ch6_init[] = { + /* set line-in and mic-in to output */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { } +}; + +static const struct hda_channel_mode alc880_lg_ch_modes[3] = { + { 2, alc880_lg_ch2_init }, + { 4, alc880_lg_ch4_init }, + { 6, alc880_lg_ch6_init }, +}; + +static const struct snd_kcontrol_new alc880_lg_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc880_lg_init_verbs[] = { + /* set capture source to mic-in */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* mute all amp mixer inputs */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + /* line-in to input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* built-in mic */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* speaker-out */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* mic-in to input */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* HP-out */ + {0x13, AC_VERB_SET_CONNECT_SEL, 0x03}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* jack sense */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc880_lg_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* + * LG LW20 + * + * Pin assignment: + * Speaker-out: 0x14 + * Mic-In: 0x18 + * Built-in Mic-In: 0x19 + * Line-In: 0x1b + * HP-Out: 0x1a + * SPDIF-Out: 0x1e + */ + +static const struct hda_input_mux alc880_lg_lw_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "Line In", 0x2 }, + }, +}; + +#define alc880_lg_lw_modes alc880_threestack_modes + +static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc880_lg_lw_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ + + /* set capture source to mic-in */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + /* speaker-out */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* HP-out */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* mic-in to input */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* built-in mic */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* jack sense */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc880_lg_lw_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_input_mux alc880_medion_rim_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + }, +}; + +static const struct hda_verb alc880_medion_rim_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Internal Speaker */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc880_medion_rim_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc_hp_automute(codec); + /* toggle EAPD */ + if (spec->jack_present) + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); + else + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2); +} + +static void alc880_medion_rim_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == ALC880_HP_EVENT) + alc880_medion_rim_automute(codec); +} + +static void alc880_medion_rim_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list alc880_loopbacks[] = { + { 0x0b, HDA_INPUT, 0 }, + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 2 }, + { 0x0b, HDA_INPUT, 3 }, + { 0x0b, HDA_INPUT, 4 }, + { } /* end */ +}; + +static const struct hda_amp_list alc880_lg_loopbacks[] = { + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 6 }, + { 0x0b, HDA_INPUT, 7 }, + { } /* end */ +}; +#endif + +/* + * Common callbacks + */ + +static void alc_init_special_input_src(struct hda_codec *codec); + +static int alc_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int i; + + alc_fix_pll(codec); + alc_auto_init_amp(codec, spec->init_amp); + + for (i = 0; i < spec->num_init_verbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); + alc_init_special_input_src(codec); + + if (spec->init_hook) + spec->init_hook(codec); + + alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); + + hda_call_check_power_status(codec, 0x01); + return 0; +} + +static void alc_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct alc_spec *spec = codec->spec; + + if (spec->unsol_event) + spec->unsol_event(codec, res); +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); +} +#endif + +/* + * Analog playback callbacks + */ +static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + hinfo); +} + +static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Digital out + */ +static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); +} + +static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +/* + * Analog capture + */ +static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], + stream_tag, 0, format); + return 0; +} + +static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + + snd_hda_codec_cleanup_stream(codec, + spec->adc_nids[substream->number + 1]); + return 0; +} + +/* analog capture with dynamic dual-adc changes */ +static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); + return 0; +} + +static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + snd_hda_codec_cleanup_stream(codec, spec->cur_adc); + spec->cur_adc = 0; + return 0; +} + +static const struct hda_pcm_stream dualmic_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .prepare = dualmic_capture_pcm_prepare, + .cleanup = dualmic_capture_pcm_cleanup + }, +}; + +/* + */ +static const struct hda_pcm_stream alc880_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + /* NID is set in alc_build_pcms */ + .ops = { + .open = alc880_playback_pcm_open, + .prepare = alc880_playback_pcm_prepare, + .cleanup = alc880_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream alc880_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ +}; + +static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ +}; + +static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = { + .substreams = 2, /* can be overridden */ + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ + .ops = { + .prepare = alc880_alt_capture_pcm_prepare, + .cleanup = alc880_alt_capture_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream alc880_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ + .ops = { + .open = alc880_dig_playback_pcm_open, + .close = alc880_dig_playback_pcm_close, + .prepare = alc880_dig_playback_pcm_prepare, + .cleanup = alc880_dig_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream alc880_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ +}; + +/* Used by alc_build_pcms to flag that a PCM has no playback stream */ +static const struct hda_pcm_stream alc_pcm_null_stream = { + .substreams = 0, + .channels_min = 0, + .channels_max = 0, +}; + +static int alc_build_pcms(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + int i; + + codec->num_pcms = 1; + codec->pcm_info = info; + + if (spec->no_analog) + goto skip_analog; + + snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), + "%s Analog", codec->chip_name); + info->name = spec->stream_name_analog; + + if (spec->stream_analog_playback) { + if (snd_BUG_ON(!spec->multiout.dac_nids)) + return -EINVAL; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + } + if (spec->stream_analog_capture) { + if (snd_BUG_ON(!spec->adc_nids)) + return -EINVAL; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + } + + if (spec->channel_mode) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; + for (i = 0; i < spec->num_channel_mode; i++) { + if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; + } + } + } + + skip_analog: + /* SPDIF for stream index #1 */ + if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + snprintf(spec->stream_name_digital, + sizeof(spec->stream_name_digital), + "%s Digital", codec->chip_name); + codec->num_pcms = 2; + codec->slave_dig_outs = spec->multiout.slave_dig_outs; + info = spec->pcm_rec + 1; + info->name = spec->stream_name_digital; + if (spec->dig_out_type) + info->pcm_type = spec->dig_out_type; + else + info->pcm_type = HDA_PCM_TYPE_SPDIF; + if (spec->multiout.dig_out_nid && + spec->stream_digital_playback) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback); + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; + } + if (spec->dig_in_nid && + spec->stream_digital_capture) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; + } + /* FIXME: do we need this for all Realtek codec models? */ + codec->spdif_status_reset = 1; + } + + if (spec->no_analog) + return 0; + + /* If the use of more than one ADC is requested for the current + * model, configure a second analog capture-only PCM. + */ + /* Additional Analaog capture for index #2 */ + if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) || + (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) { + codec->num_pcms = 3; + info = spec->pcm_rec + 2; + info->name = spec->stream_name_analog; + if (spec->alt_dac_nid) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + *spec->stream_analog_alt_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->alt_dac_nid; + } else { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + alc_pcm_null_stream; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; + } + if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + *spec->stream_analog_alt_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = + spec->adc_nids[1]; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = + spec->num_adc_nids - 1; + } else { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + alc_pcm_null_stream; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; + } + } + + return 0; +} + +static inline void alc_shutup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec && spec->shutup) + spec->shutup(codec); + snd_hda_shutup_pins(codec); +} + +static void alc_free_kctls(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec->kctls.list) { + struct snd_kcontrol_new *kctl = spec->kctls.list; + int i; + for (i = 0; i < spec->kctls.used; i++) + kfree(kctl[i].name); + } + snd_array_free(&spec->kctls); +} + +static void alc_free(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec) + return; + + alc_shutup(codec); + snd_hda_input_jack_free(codec); + alc_free_kctls(codec); + kfree(spec); + snd_hda_detach_beep_device(codec); +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void alc_power_eapd(struct hda_codec *codec) +{ + alc_auto_setup_eapd(codec, false); +} + +static int alc_suspend(struct hda_codec *codec, pm_message_t state) +{ + struct alc_spec *spec = codec->spec; + alc_shutup(codec); + if (spec && spec->power_hook) + spec->power_hook(codec); + return 0; +} +#endif + +#ifdef SND_HDA_NEEDS_RESUME +static int alc_resume(struct hda_codec *codec) +{ + msleep(150); /* to avoid pop noise */ + codec->patch_ops.init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + hda_call_check_power_status(codec, 0x01); + return 0; +} +#endif + +/* + */ +static const struct hda_codec_ops alc_patch_ops = { + .build_controls = alc_build_controls, + .build_pcms = alc_build_pcms, + .init = alc_init, + .free = alc_free, + .unsol_event = alc_unsol_event, +#ifdef SND_HDA_NEEDS_RESUME + .resume = alc_resume, +#endif +#ifdef CONFIG_SND_HDA_POWER_SAVE + .suspend = alc_suspend, + .check_power_status = alc_check_power_status, +#endif + .reboot_notify = alc_shutup, +}; + +/* replace the codec chip_name with the given string */ +static int alc_codec_rename(struct hda_codec *codec, const char *name) +{ + kfree(codec->chip_name); + codec->chip_name = kstrdup(name, GFP_KERNEL); + if (!codec->chip_name) { + alc_free(codec); + return -ENOMEM; + } + return 0; +} + +/* + * Test configuration for debugging + * + * Almost all inputs/outputs are enabled. I/O pins can be configured via + * enum controls. + */ +#ifdef CONFIG_SND_DEBUG +static const hda_nid_t alc880_test_dac_nids[4] = { + 0x02, 0x03, 0x04, 0x05 +}; + +static const struct hda_input_mux alc880_test_capture_source = { + .num_items = 7, + .items = { + { "In-1", 0x0 }, + { "In-2", 0x1 }, + { "In-3", 0x2 }, + { "In-4", 0x3 }, + { "CD", 0x4 }, + { "Front", 0x5 }, + { "Surround", 0x6 }, + }, +}; + +static const struct hda_channel_mode alc880_test_modes[4] = { + { 2, NULL }, + { 4, NULL }, + { 6, NULL }, + { 8, NULL }, +}; + +static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[] = { + "N/A", "Line Out", "HP Out", + "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 8; + if (uinfo->value.enumerated.item >= 8) + uinfo->value.enumerated.item = 7; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int pin_ctl, item = 0; + + pin_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (pin_ctl & AC_PINCTL_OUT_EN) { + if (pin_ctl & AC_PINCTL_HP_EN) + item = 2; + else + item = 1; + } else if (pin_ctl & AC_PINCTL_IN_EN) { + switch (pin_ctl & AC_PINCTL_VREFEN) { + case AC_PINCTL_VREF_HIZ: item = 3; break; + case AC_PINCTL_VREF_50: item = 4; break; + case AC_PINCTL_VREF_GRD: item = 5; break; + case AC_PINCTL_VREF_80: item = 6; break; + case AC_PINCTL_VREF_100: item = 7; break; + } + } + ucontrol->value.enumerated.item[0] = item; + return 0; +} + +static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + static const unsigned int ctls[] = { + 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, + }; + unsigned int old_ctl, new_ctl; + + old_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + new_ctl = ctls[ucontrol->value.enumerated.item[0]]; + if (old_ctl != new_ctl) { + int val; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + new_ctl); + val = ucontrol->value.enumerated.item[0] >= 3 ? + HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, val); + return 1; + } + return 0; +} + +static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[] = { + "Front", "Surround", "CLFE", "Side" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item >= 4) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int sel; + + sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); + ucontrol->value.enumerated.item[0] = sel & 3; + return 0; +} + +static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int sel; + + sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; + if (ucontrol->value.enumerated.item[0] != sel) { + sel = ucontrol->value.enumerated.item[0] & 3; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, sel); + return 1; + } + return 0; +} + +#define PIN_CTL_TEST(xname,nid) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_test_pin_ctl_info, \ + .get = alc_test_pin_ctl_get, \ + .put = alc_test_pin_ctl_put, \ + .private_value = nid \ + } + +#define PIN_SRC_TEST(xname,nid) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_test_pin_src_info, \ + .get = alc_test_pin_src_get, \ + .put = alc_test_pin_src_put, \ + .private_value = nid \ + } + +static const struct snd_kcontrol_new alc880_test_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + PIN_CTL_TEST("Front Pin Mode", 0x14), + PIN_CTL_TEST("Surround Pin Mode", 0x15), + PIN_CTL_TEST("CLFE Pin Mode", 0x16), + PIN_CTL_TEST("Side Pin Mode", 0x17), + PIN_CTL_TEST("In-1 Pin Mode", 0x18), + PIN_CTL_TEST("In-2 Pin Mode", 0x19), + PIN_CTL_TEST("In-3 Pin Mode", 0x1a), + PIN_CTL_TEST("In-4 Pin Mode", 0x1b), + PIN_SRC_TEST("In-1 Pin Source", 0x18), + PIN_SRC_TEST("In-2 Pin Source", 0x19), + PIN_SRC_TEST("In-3 Pin Source", 0x1a), + PIN_SRC_TEST("In-4 Pin Source", 0x1b), + HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc880_test_init_verbs[] = { + /* Unmute inputs of 0x0c - 0x0f */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* Vol output for 0x0c-0x0f */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* Set output pins 0x14-0x17 */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* Unmute output pins 0x14-0x17 */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Set input pins 0x18-0x1c */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Mute input pins 0x18-0x1b */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* ADC set up */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Analog input/passthru */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + { } +}; +#endif + +/* + */ + +static const char * const alc880_models[ALC880_MODEL_LAST] = { + [ALC880_3ST] = "3stack", + [ALC880_TCL_S700] = "tcl", + [ALC880_3ST_DIG] = "3stack-digout", + [ALC880_CLEVO] = "clevo", + [ALC880_5ST] = "5stack", + [ALC880_5ST_DIG] = "5stack-digout", + [ALC880_W810] = "w810", + [ALC880_Z71V] = "z71v", + [ALC880_6ST] = "6stack", + [ALC880_6ST_DIG] = "6stack-digout", + [ALC880_ASUS] = "asus", + [ALC880_ASUS_W1V] = "asus-w1v", + [ALC880_ASUS_DIG] = "asus-dig", + [ALC880_ASUS_DIG2] = "asus-dig2", + [ALC880_UNIWILL_DIG] = "uniwill", + [ALC880_UNIWILL_P53] = "uniwill-p53", + [ALC880_FUJITSU] = "fujitsu", + [ALC880_F1734] = "F1734", + [ALC880_LG] = "lg", + [ALC880_LG_LW] = "lg-lw", + [ALC880_MEDION_RIM] = "medion", +#ifdef CONFIG_SND_DEBUG + [ALC880_TEST] = "test", +#endif + [ALC880_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc880_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), + SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), + SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), + SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), + SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V), + /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */ + SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), + SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), + SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */ + SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), + SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), + SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), + SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), + SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), + SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), + SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734), + SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), + SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), + SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), + SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM), + SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), + SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), + SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734), + SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), + SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), + SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), + SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), + SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */ + SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), + SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), + /* default Intel */ + SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST), + SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), + SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), + {} +}; + +/* + * ALC880 codec presets + */ +static const struct alc_config_preset alc880_presets[] = { + [ALC880_3ST] = { + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_3ST_DIG] = { + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_TCL_S700] = { + .mixers = { alc880_tcl_s700_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_tcl_S700_init_verbs, + alc880_gpio2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */ + .num_adc_nids = 1, /* single ADC */ + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_5ST] = { + .mixers = { alc880_three_stack_mixer, + alc880_five_stack_mixer}, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_5stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), + .channel_mode = alc880_fivestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_5ST_DIG] = { + .mixers = { alc880_three_stack_mixer, + alc880_five_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_5stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), + .channel_mode = alc880_fivestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_6ST] = { + .mixers = { alc880_six_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_6stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), + .dac_nids = alc880_6st_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), + .channel_mode = alc880_sixstack_modes, + .input_mux = &alc880_6stack_capture_source, + }, + [ALC880_6ST_DIG] = { + .mixers = { alc880_six_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_6stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), + .dac_nids = alc880_6st_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), + .channel_mode = alc880_sixstack_modes, + .input_mux = &alc880_6stack_capture_source, + }, + [ALC880_W810] = { + .mixers = { alc880_w810_base_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_w810_init_verbs, + alc880_gpio2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), + .channel_mode = alc880_w810_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_Z71V] = { + .mixers = { alc880_z71v_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_z71v_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), + .dac_nids = alc880_z71v_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_F1734] = { + .mixers = { alc880_f1734_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_f1734_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), + .dac_nids = alc880_f1734_dac_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_f1734_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_ASUS] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_DIG] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_DIG2] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio2_init_verbs }, /* use GPIO2 */ + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_W1V] = { + .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_UNIWILL_DIG] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_UNIWILL] = { + .mixers = { alc880_uniwill_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_unsol_event, + .setup = alc880_uniwill_setup, + .init_hook = alc880_uniwill_init_hook, + }, + [ALC880_UNIWILL_P53] = { + .mixers = { alc880_uniwill_p53_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_p53_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_FUJITSU] = { + .mixers = { alc880_fujitsu_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_p53_init_verbs, + alc880_beep_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_CLEVO] = { + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_clevo_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_LG] = { + .mixers = { alc880_lg_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_lg_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids), + .dac_nids = alc880_lg_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), + .channel_mode = alc880_lg_ch_modes, + .need_dac_fix = 1, + .input_mux = &alc880_lg_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc880_lg_setup, + .init_hook = alc_hp_automute, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .loopbacks = alc880_lg_loopbacks, +#endif + }, + [ALC880_LG_LW] = { + .mixers = { alc880_lg_lw_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_lg_lw_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), + .channel_mode = alc880_lg_lw_modes, + .input_mux = &alc880_lg_lw_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc880_lg_lw_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_MEDION_RIM] = { + .mixers = { alc880_medion_rim_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_medion_rim_init_verbs, + alc_gpio2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_medion_rim_capture_source, + .unsol_event = alc880_medion_rim_unsol_event, + .setup = alc880_medion_rim_setup, + .init_hook = alc880_medion_rim_automute, + }, +#ifdef CONFIG_SND_DEBUG + [ALC880_TEST] = { + .mixers = { alc880_test_mixer }, + .init_verbs = { alc880_test_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), + .dac_nids = alc880_test_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_test_modes), + .channel_mode = alc880_test_modes, + .input_mux = &alc880_test_capture_source, + }, +#endif +}; + +/* + * Automatic parse of I/O pins from the BIOS configuration + */ + +enum { + ALC_CTL_WIDGET_VOL, + ALC_CTL_WIDGET_MUTE, + ALC_CTL_BIND_MUTE, +}; +static const struct snd_kcontrol_new alc880_control_templates[] = { + HDA_CODEC_VOLUME(NULL, 0, 0, 0), + HDA_CODEC_MUTE(NULL, 0, 0, 0), + HDA_BIND_MUTE(NULL, 0, 0, 0), +}; + +static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec) +{ + snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); + return snd_array_new(&spec->kctls); +} + +/* add dynamic controls */ +static int add_control(struct alc_spec *spec, int type, const char *name, + int cidx, unsigned long val) +{ + struct snd_kcontrol_new *knew; + + knew = alc_kcontrol_new(spec); if (!knew) return -ENOMEM; - *knew = alc_control_templates[type]; - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) + *knew = alc880_control_templates[type]; + knew->name = kstrdup(name, GFP_KERNEL); + if (!knew->name) + return -ENOMEM; + knew->index = cidx; + if (get_amp_nid_(val)) + knew->subdevice = HDA_SUBDEV_AMP_FLAG; + knew->private_value = val; + return 0; +} + +static int add_control_with_pfx(struct alc_spec *spec, int type, + const char *pfx, const char *dir, + const char *sfx, int cidx, unsigned long val) +{ + char name[32]; + snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); + return add_control(spec, type, name, cidx, val); +} + +#define add_pb_vol_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) +#define add_pb_sw_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) +#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) +#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) + +#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) +#define alc880_fixed_pin_idx(nid) ((nid) - 0x14) +#define alc880_is_multi_pin(nid) ((nid) >= 0x18) +#define alc880_multi_pin_idx(nid) ((nid) - 0x18) +#define alc880_idx_to_dac(nid) ((nid) + 0x02) +#define alc880_dac_to_idx(nid) ((nid) - 0x02) +#define alc880_idx_to_mixer(nid) ((nid) + 0x0c) +#define alc880_idx_to_selector(nid) ((nid) + 0x10) +#define ALC880_PIN_CD_NID 0x1c + +/* fill in the dac_nids table from the parsed pin configuration */ +static int alc880_auto_fill_dac_nids(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int assigned[4]; + int i, j; + + memset(assigned, 0, sizeof(assigned)); + spec->multiout.dac_nids = spec->private_dac_nids; + + /* check the pins hardwired to audio widget */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (alc880_is_fixed_pin(nid)) { + int idx = alc880_fixed_pin_idx(nid); + spec->private_dac_nids[i] = alc880_idx_to_dac(idx); + assigned[idx] = 1; + } + } + /* left pins can be connect to any audio widget */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (alc880_is_fixed_pin(nid)) + continue; + /* search for an empty channel */ + for (j = 0; j < cfg->line_outs; j++) { + if (!assigned[j]) { + spec->private_dac_nids[i] = + alc880_idx_to_dac(j); + assigned[j] = 1; + break; + } + } + } + spec->multiout.num_dacs = cfg->line_outs; + return 0; +} + +static const char *alc_get_line_out_pfx(struct alc_spec *spec, + bool can_be_master) +{ + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (cfg->line_outs == 1 && !spec->multi_ios && + !cfg->hp_outs && !cfg->speaker_outs && can_be_master) + return "Master"; + + switch (cfg->line_out_type) { + case AUTO_PIN_SPEAKER_OUT: + if (cfg->line_outs == 1) + return "Speaker"; + break; + case AUTO_PIN_HP_OUT: + return "Headphone"; + default: + if (cfg->line_outs == 1 && !spec->multi_ios) + return "PCM"; + break; + } + return NULL; +} + +/* add playback controls from the parsed DAC table */ +static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static const char * const chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; + const char *pfx = alc_get_line_out_pfx(spec, false); + hda_nid_t nid; + int i, err, noutputs; + + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { + if (!spec->multiout.dac_nids[i]) + continue; + nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); + if (!pfx && i == 2) { + /* Center/LFE */ + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "Center", + HDA_COMPOSE_AMP_VAL(nid, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "LFE", + HDA_COMPOSE_AMP_VAL(nid, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "Center", + HDA_COMPOSE_AMP_VAL(nid, 1, 2, + HDA_INPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "LFE", + HDA_COMPOSE_AMP_VAL(nid, 2, 2, + HDA_INPUT)); + if (err < 0) + return err; + } else { + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + name, index, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + name, index, + HDA_COMPOSE_AMP_VAL(nid, 3, 2, + HDA_INPUT)); + if (err < 0) + return err; + } + } + return 0; +} + +/* add playback controls for speaker and HP outputs */ +static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, + const char *pfx) +{ + hda_nid_t nid; + int err; + + if (!pin) + return 0; + + if (alc880_is_fixed_pin(pin)) { + nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); + /* specify the DAC as the extra output */ + if (!spec->multiout.hp_nid) + spec->multiout.hp_nid = nid; + else + spec->multiout.extra_out_nid[0] = nid; + /* control HP volume/switch on the output mixer amp */ + nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); + if (err < 0) + return err; + } else if (alc880_is_multi_pin(pin)) { + /* set manual connection */ + /* we have only a switch on HP-out PIN */ + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } + return 0; +} + +/* create input playback/capture controls for the given pin */ +static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, + const char *ctlname, int ctlidx, + int idx, hda_nid_t mix_nid) +{ + int err; + + err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx, + HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); + if (err < 0) + return err; + err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx, + HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); + if (err < 0) + return err; + return 0; +} + +static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int pincap = snd_hda_query_pin_caps(codec, nid); + return (pincap & AC_PINCAP_IN) != 0; +} + +/* create playback/capture controls for input pins */ +static int alc_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + hda_nid_t mixer, + hda_nid_t cap1, hda_nid_t cap2) +{ + struct alc_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx, type_idx = 0; + const char *prev_label = NULL; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t pin; + const char *label; + + pin = cfg->inputs[i].pin; + if (!alc_is_input_pin(codec, pin)) + continue; + + label = hda_get_autocfg_input_label(codec, cfg, i); + if (prev_label && !strcmp(label, prev_label)) + type_idx++; + else + type_idx = 0; + prev_label = label; + + if (mixer) { + idx = get_connection_index(codec, mixer, pin); + if (idx >= 0) { + err = new_analog_input(spec, pin, + label, type_idx, + idx, mixer); + if (err < 0) + return err; + } + } + + if (!cap1) + continue; + idx = get_connection_index(codec, cap1, pin); + if (idx < 0 && cap2) + idx = get_connection_index(codec, cap2, pin); + if (idx >= 0) + snd_hda_add_imux_item(imux, label, idx, NULL); + } + return 0; +} + +static int alc880_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09); +} + +static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid, + unsigned int pin_type) +{ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_type); + /* unmute pin */ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); +} + +static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + int dac_idx) +{ + alc_set_pin_output(codec, nid, pin_type); + /* need the manual connection? */ + if (alc880_is_multi_pin(nid)) { + struct alc_spec *spec = codec->spec; + int idx = alc880_multi_pin_idx(nid); + snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, + AC_VERB_SET_CONNECT_SEL, + alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); + } +} + +static int get_pin_type(int line_out_type) +{ + if (line_out_type == AUTO_PIN_HP_OUT) + return PIN_HP; + else + return PIN_OUT; +} + +static void alc880_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc880_auto_set_output_and_unmute(codec, nid, pin_type, i); + } +} + +static void alc880_auto_init_extra_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + + pin = spec->autocfg.speaker_pins[0]; + if (pin) /* connect to front */ + alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); + pin = spec->autocfg.hp_pins[0]; + if (pin) /* connect to front */ + alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); +} + +static void alc880_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (alc_is_input_pin(codec, nid)) { + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + if (nid != ALC880_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } + } +} + +static void alc880_auto_init_input_src(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int c; + + for (c = 0; c < spec->num_adc_nids; c++) { + unsigned int mux_idx; + const struct hda_input_mux *imux; + mux_idx = c >= spec->num_mux_defs ? 0 : c; + imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; + if (imux) + snd_hda_codec_write(codec, spec->adc_nids[c], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[0].index); + } +} + +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec); + +/* parse the BIOS configuration and set up the alc_spec */ +/* return 1 if successful, 0 if the proper config is not found, + * or a negative error code + */ +static int alc880_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc880_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) + return 0; /* can't find valid BIOS pin config */ + + err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; + err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, + spec->autocfg.speaker_pins[0], + "Speaker"); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], + "Headphone"); + if (err < 0) + return err; + err = alc880_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + alc_auto_parse_digital(codec); + + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc880_volume_init_verbs); + + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + return 1; +} + +/* additional initialization for auto-configuration model */ +static void alc880_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc880_auto_init_multi_out(codec); + alc880_auto_init_extra_out(codec); + alc880_auto_init_analog_input(codec); + alc880_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +/* check the ADC/MUX contains all input pins; some ADC/MUX contains only + * one of two digital mic pins, e.g. on ALC272 + */ +static void fixup_automic_adc(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_adc_nids; i++) { + hda_nid_t cap = spec->capsrc_nids ? + spec->capsrc_nids[i] : spec->adc_nids[i]; + int iidx, eidx; + + iidx = get_connection_index(codec, cap, spec->int_mic.pin); + if (iidx < 0) + continue; + eidx = get_connection_index(codec, cap, spec->ext_mic.pin); + if (eidx < 0) + continue; + spec->int_mic.mux_idx = iidx; + spec->ext_mic.mux_idx = eidx; + if (spec->capsrc_nids) + spec->capsrc_nids += i; + spec->adc_nids += i; + spec->num_adc_nids = 1; + /* optional dock-mic */ + eidx = get_connection_index(codec, cap, spec->dock_mic.pin); + if (eidx < 0) + spec->dock_mic.pin = 0; + else + spec->dock_mic.mux_idx = eidx; + return; + } + snd_printd(KERN_INFO "hda_codec: %s: " + "No ADC/MUX containing both 0x%x and 0x%x pins\n", + codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin); + spec->auto_mic = 0; /* disable auto-mic to be sure */ +} + +/* select or unmute the given capsrc route */ +static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, + int idx) +{ + if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { + snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, + HDA_AMP_MUTE, 0); + } else { + snd_hda_codec_write_cache(codec, cap, 0, + AC_VERB_SET_CONNECT_SEL, idx); + } +} + +/* set the default connection to that pin */ +static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) +{ + struct alc_spec *spec = codec->spec; + int i; + + if (!pin) + return 0; + for (i = 0; i < spec->num_adc_nids; i++) { + hda_nid_t cap = spec->capsrc_nids ? + spec->capsrc_nids[i] : spec->adc_nids[i]; + int idx; + + idx = get_connection_index(codec, cap, pin); + if (idx < 0) + continue; + select_or_unmute_capsrc(codec, cap, idx); + return i; /* return the found index */ + } + return -1; /* not found */ +} + +/* choose the ADC/MUX containing the input pin and initialize the setup */ +static void fixup_single_adc(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + /* search for the input pin; there must be only one */ + if (cfg->num_inputs != 1) + return; + i = init_capsrc_for_pin(codec, cfg->inputs[0].pin); + if (i >= 0) { + /* use only this ADC */ + if (spec->capsrc_nids) + spec->capsrc_nids += i; + spec->adc_nids += i; + spec->num_adc_nids = 1; + spec->single_input_src = 1; + } +} + +/* initialize dual adcs */ +static void fixup_dual_adc_switch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + init_capsrc_for_pin(codec, spec->ext_mic.pin); + init_capsrc_for_pin(codec, spec->dock_mic.pin); + init_capsrc_for_pin(codec, spec->int_mic.pin); +} + +/* initialize some special cases for input sources */ +static void alc_init_special_input_src(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + if (spec->dual_adc_switch) + fixup_dual_adc_switch(codec); + else if (spec->single_input_src) + init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin); +} + +static void set_capture_mixer(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + static const struct snd_kcontrol_new *caps[2][3] = { + { alc_capture_mixer_nosrc1, + alc_capture_mixer_nosrc2, + alc_capture_mixer_nosrc3 }, + { alc_capture_mixer1, + alc_capture_mixer2, + alc_capture_mixer3 }, + }; + if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { + int mux = 0; + int num_adcs = spec->num_adc_nids; + if (spec->dual_adc_switch) + num_adcs = 1; + else if (spec->auto_mic) + fixup_automic_adc(codec); + else if (spec->input_mux) { + if (spec->input_mux->num_items > 1) + mux = 1; + else if (spec->input_mux->num_items == 1) + fixup_single_adc(codec); + } + spec->cap_mixer = caps[mux][num_adcs - 1]; + } +} + +/* fill adc_nids (and capsrc_nids) containing all active input pins */ +static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids, + int num_nids) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int n; + hda_nid_t fallback_adc = 0, fallback_cap = 0; + + for (n = 0; n < num_nids; n++) { + hda_nid_t adc, cap; + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int nconns, i, j; + + adc = nids[n]; + if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN) + continue; + cap = adc; + nconns = snd_hda_get_connections(codec, cap, conn, + ARRAY_SIZE(conn)); + if (nconns == 1) { + cap = conn[0]; + nconns = snd_hda_get_connections(codec, cap, conn, + ARRAY_SIZE(conn)); + } + if (nconns <= 0) + continue; + if (!fallback_adc) { + fallback_adc = adc; + fallback_cap = cap; + } + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + for (j = 0; j < nconns; j++) { + if (conn[j] == nid) + break; + } + if (j >= nconns) + break; + } + if (i >= cfg->num_inputs) { + int num_adcs = spec->num_adc_nids; + spec->private_adc_nids[num_adcs] = adc; + spec->private_capsrc_nids[num_adcs] = cap; + spec->num_adc_nids++; + spec->adc_nids = spec->private_adc_nids; + if (adc != cap) + spec->capsrc_nids = spec->private_capsrc_nids; + } + } + if (!spec->num_adc_nids) { + printk(KERN_WARNING "hda_codec: %s: no valid ADC found;" + " using fallback 0x%x\n", + codec->chip_name, fallback_adc); + spec->private_adc_nids[0] = fallback_adc; + spec->adc_nids = spec->private_adc_nids; + if (fallback_adc != fallback_cap) { + spec->private_capsrc_nids[0] = fallback_cap; + spec->capsrc_nids = spec->private_adc_nids; + } + } +} + +#ifdef CONFIG_SND_HDA_INPUT_BEEP +#define set_beep_amp(spec, nid, idx, dir) \ + ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) + +static const struct snd_pci_quirk beep_white_list[] = { + SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), + SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), + SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), + {} +}; + +static inline int has_cdefine_beep(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + const struct snd_pci_quirk *q; + q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list); + if (q) + return q->value; + return spec->cdefine.enable_pcbeep; +} +#else +#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#define has_cdefine_beep(codec) 0 +#endif + +/* + * OK, here we have finally the patch for ALC880 + */ + +static int patch_alc880(struct hda_codec *codec) +{ + struct alc_spec *spec; + int board_config; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST, + alc880_models, + alc880_cfg_tbl); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC880_AUTO; + } + + if (board_config == ALC880_AUTO) { + /* automatic parse from the BIOS config */ + err = alc880_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using 3-stack mode...\n"); + board_config = ALC880_3ST; + } + } + + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + + if (board_config != ALC880_AUTO) + setup_preset(codec, &alc880_presets[board_config]); + + spec->stream_analog_playback = &alc880_pcm_analog_playback; + spec->stream_analog_capture = &alc880_pcm_analog_capture; + spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; + + spec->stream_digital_playback = &alc880_pcm_digital_playback; + spec->stream_digital_capture = &alc880_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + /* check whether NID 0x07 is valid */ + unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]); + /* get type */ + wcap = get_wcaps_type(wcap); + if (wcap != AC_WID_AUD_IN) { + spec->adc_nids = alc880_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); + } else { + spec->adc_nids = alc880_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); + } + } + set_capture_mixer(codec); + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + + spec->vmaster_nid = 0x0c; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC880_AUTO) + spec->init_hook = alc880_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc880_loopbacks; +#endif + + return 0; +} + + +/* + * ALC260 support + */ + +static const hda_nid_t alc260_dac_nids[1] = { + /* front */ + 0x02, +}; + +static const hda_nid_t alc260_adc_nids[1] = { + /* ADC0 */ + 0x04, +}; + +static const hda_nid_t alc260_adc_nids_alt[1] = { + /* ADC1 */ + 0x05, +}; + +/* NIDs used when simultaneous access to both ADCs makes sense. Note that + * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. + */ +static const hda_nid_t alc260_dual_adc_nids[2] = { + /* ADC0, ADC1 */ + 0x04, 0x05 +}; + +#define ALC260_DIGOUT_NID 0x03 +#define ALC260_DIGIN_NID 0x06 + +static const struct hda_input_mux alc260_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack, + * headphone jack and the internal CD lines since these are the only pins at + * which audio can appear. For flexibility, also allow the option of + * recording the mixer output on the second ADC (ADC0 doesn't have a + * connection to the mixer output). + */ +static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = { + { + .num_items = 3, + .items = { + { "Mic/Line", 0x0 }, + { "CD", 0x4 }, + { "Headphone", 0x2 }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic/Line", 0x0 }, + { "CD", 0x4 }, + { "Headphone", 0x2 }, + { "Mixer", 0x5 }, + }, + }, + +}; + +/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to + * the Fujitsu S702x, but jacks are marked differently. + */ +static const struct hda_input_mux alc260_acer_capture_sources[2] = { + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Headphone", 0x5 }, + }, + }, + { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Headphone", 0x6 }, + { "Mixer", 0x5 }, + }, + }, +}; + +/* Maxdata Favorit 100XS */ +static const struct hda_input_mux alc260_favorit100_capture_sources[2] = { + { + .num_items = 2, + .items = { + { "Line/Mic", 0x0 }, + { "CD", 0x4 }, + }, + }, + { + .num_items = 3, + .items = { + { "Line/Mic", 0x0 }, + { "CD", 0x4 }, + { "Mixer", 0x5 }, + }, + }, +}; + +/* + * This is just place-holder, so there's something for alc_build_pcms to look + * at when it calculates the maximum number of channels. ALC260 has no mixer + * element which allows changing the channel mode, so the verb list is + * never used. + */ +static const struct hda_channel_mode alc260_modes[1] = { + { 2, NULL }, +}; + + +/* Mixer combinations + * + * basic: base_output + input + pc_beep + capture + * HP: base_output + input + capture_alt + * HP_3013: hp_3013 + input + capture + * fujitsu: fujitsu + capture + * acer: acer + capture + */ + +static const struct snd_kcontrol_new alc260_base_output_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc260_input_mixer[] = { + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), + { } /* end */ +}; + +/* update HP, line and mono out pins according to the master switch */ +static void alc260_hp_master_update(struct hda_codec *codec) +{ + update_speakers(codec); +} + +static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + *ucontrol->value.integer.value = !spec->master_mute; + return 0; +} + +static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int val = !*ucontrol->value.integer.value; + + if (val == spec->master_mute) + return 0; + spec->master_mute = val; + alc260_hp_master_update(codec); + return 1; +} + +static const struct snd_kcontrol_new alc260_hp_output_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, + .info = snd_ctl_boolean_mono_info, + .get = alc260_hp_master_sw_get, + .put = alc260_hp_master_sw_put, + }, + HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc260_hp_unsol_verbs[] = { + {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {}, +}; + +static void alc260_hp_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x0f; + spec->autocfg.speaker_pins[0] = 0x10; + spec->autocfg.speaker_pins[1] = 0x11; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, + .info = snd_ctl_boolean_mono_info, + .get = alc260_hp_master_sw_get, + .put = alc260_hp_master_sw_put, + }, + HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static void alc260_hp_3013_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x10; + spec->autocfg.speaker_pins[1] = 0x11; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc260_dc7600_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol), + HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct hda_verb alc260_hp_3013_unsol_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {}, +}; + +static void alc260_hp_3012_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x10; + spec->autocfg.speaker_pins[0] = 0x0f; + spec->autocfg.speaker_pins[1] = 0x11; + spec->autocfg.speaker_pins[2] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, + * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. + */ +static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT), + { } /* end */ +}; + +/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current + * versions of the ALC260 don't act on requests to enable mic bias from NID + * 0x0f (used to drive the headphone jack in these laptops). The ALC260 + * datasheet doesn't mention this restriction. At this stage it's not clear + * whether this behaviour is intentional or is a hardware bug in chip + * revisions available in early 2006. Therefore for now allow the + * "Headphone Jack Mode" control to span all choices, but if it turns out + * that the lack of mic bias for this NID is intentional we could change the + * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. + * + * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006 + * don't appear to make the mic bias available from the "line" jack, even + * though the NID used for this jack (0x14) can supply it. The theory is + * that perhaps Acer have included blocking capacitors between the ALC260 + * and the output jack. If this turns out to be the case for all such + * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT + * to ALC_PIN_DIR_INOUT_NOMICBIAS. + * + * The C20x Tablet series have a mono internal speaker which is controlled + * via the chip's Mono sum widget and pin complex, so include the necessary + * controls for such models. On models without a "mono speaker" the control + * won't do anything. + */ +static const struct snd_kcontrol_new alc260_acer_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, + HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + { } /* end */ +}; + +/* Maxdata Favorit 100XS: one output and one input (0x12) jack + */ +static const struct snd_kcontrol_new alc260_favorit100_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + { } /* end */ +}; + +/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12, + * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17. + */ +static const struct snd_kcontrol_new alc260_will_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + { } /* end */ +}; + +/* Replacer 672V ALC260 pin usage: Mic jack = 0x12, + * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f. + */ +static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + { } /* end */ +}; + +/* + * initialization verbs + */ +static const struct hda_verb alc260_init_verbs[] = { + /* Line In pin widget for input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* CD pin widget for input */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + /* LINE-2 is used for line-out in rear */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* select line-out */ + {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* LINE-OUT pin */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* enable HP */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* enable Mono */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* set connection select to line in (default select for this ADC) */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* mute capture amp left and right */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* set connection select to line in (default select for this ADC) */ + {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* set vol=0 Line-Out mixer amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 HP mixer amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 Mono mixer amp left and right */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* unmute LINE-2 out pin */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & + * Line In 2 = 0x03 + */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* mute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* mute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* mute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + { } +}; + +#if 0 /* should be identical with alc260_init_verbs? */ +static const struct hda_verb alc260_hp_init_verbs[] = { + /* Headphone and output */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + /* mono output */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Line In pin widget for input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* Line-2 pin widget for output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* CD pin widget for input */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* unmute amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to line in (default select for this ADC) */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* unmute Line-Out mixer amp left and right (volume = 0) */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* unmute HP mixer amp left and right (volume = 0) */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & + * Line In 2 = 0x03 + */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* Unmute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + { } +}; +#endif + +static const struct hda_verb alc260_hp_3013_init_verbs[] = { + /* Line out and output */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* mono output */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Line In pin widget for input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* Headphone pin widget for output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + /* CD pin widget for input */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* unmute amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to line in (default select for this ADC) */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* unmute Line-Out mixer amp left and right (volume = 0) */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* unmute HP mixer amp left and right (volume = 0) */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & + * Line In 2 = 0x03 + */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* Unmute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + { } +}; + +/* Initialisation sequence for ALC260 as configured in Fujitsu S702x + * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD + * audio = 0x16, internal speaker = 0x10. + */ +static const struct hda_verb alc260_fujitsu_init_verbs[] = { + /* Disable all GPIOs */ + {0x01, AC_VERB_SET_GPIO_MASK, 0}, + /* Internal speaker is connected to headphone pin */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Headphone/Line-out jack connects to Line1 pin; make it an output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Ensure all other unused pins are disabled and muted. */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Line1 pin widget takes its input from the OUT1 sum bus + * when acting as an output. + */ + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Line1 pin widget output buffer since it starts as an output. + * If the pin mode is changed by the user the pin mode control will + * take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute input buffer of pin widget used for Line-in (no equiv + * mixer ctrl) + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - line + * in (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do the same for the second ADC: mute capture input amp and + * set ADC connection to line in (on mic1 pin) + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + +/* Initialisation sequence for ALC260 as configured in Acer TravelMate and + * similar laptops (adapted from Fujitsu init verbs). + */ +static const struct hda_verb alc260_acer_init_verbs[] = { + /* On TravelMate laptops, GPIO 0 enables the internal speaker and + * the headphone jack. Turn this on and rely on the standard mute + * methods whenever the user wants to turn these outputs off. + */ + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + /* Internal speaker/Headphone jack is connected to Line-out pin */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Internal microphone/Mic jack is connected to Mic1 pin */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + /* Line In jack is connected to Line1 pin */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Ensure all other unused pins are disabled and muted. */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum + * bus when acting as outputs. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute Line-out pin widget amp left and right + * (no equiv mixer ctrl) + */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute mono pin widget amp output (no equiv mixer ctrl) */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mic1 and Line1 pin widget input buffers since they start as + * inputs. If the pin mode is changed by the user the pin mode control + * will take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - mic + * (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do similar with the second ADC: mute capture input amp and + * set ADC connection to mic to match ALSA's default state. + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + +/* Initialisation sequence for Maxdata Favorit 100XS + * (adapted from Acer init verbs). + */ +static const struct hda_verb alc260_favorit100_init_verbs[] = { + /* GPIO 0 enables the output jack. + * Turn this on and rely on the standard mute + * methods whenever the user wants to turn these outputs off. + */ + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + /* Line/Mic input jack is connected to Mic1 pin */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + /* Ensure all other unused pins are disabled and muted. */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum + * bus when acting as outputs. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute Line-out pin widget amp left and right + * (no equiv mixer ctrl) + */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mic1 and Line1 pin widget input buffers since they start as + * inputs. If the pin mode is changed by the user the pin mode control + * will take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - mic + * (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do similar with the second ADC: mute capture input amp and + * set ADC connection to mic to match ALSA's default state. + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + +static const struct hda_verb alc260_will_verbs[] = { + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x1a, AC_VERB_SET_PROC_COEF, 0x3040}, + {} +}; + +static const struct hda_verb alc260_replacer_672v_verbs[] = { + {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x1a, AC_VERB_SET_PROC_COEF, 0x3050}, + + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + + {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc260_replacer_672v_automute(struct hda_codec *codec) +{ + unsigned int present; + + /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */ + present = snd_hda_jack_detect(codec, 0x0f); + if (present) { + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 1); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_HP); + } else { + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 0); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + } +} + +static void alc260_replacer_672v_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc260_replacer_672v_automute(codec); +} + +static const struct hda_verb alc260_hp_dc7600_verbs[] = { + {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +/* Test configuration for debugging, modelled after the ALC880 test + * configuration. + */ +#ifdef CONFIG_SND_DEBUG +static const hda_nid_t alc260_test_dac_nids[1] = { + 0x02, +}; +static const hda_nid_t alc260_test_adc_nids[2] = { + 0x04, 0x05, +}; +/* For testing the ALC260, each input MUX needs its own definition since + * the signal assignments are different. This assumes that the first ADC + * is NID 0x04. + */ +static const struct hda_input_mux alc260_test_capture_sources[2] = { + { + .num_items = 7, + .items = { + { "MIC1 pin", 0x0 }, + { "MIC2 pin", 0x1 }, + { "LINE1 pin", 0x2 }, + { "LINE2 pin", 0x3 }, + { "CD pin", 0x4 }, + { "LINE-OUT pin", 0x5 }, + { "HP-OUT pin", 0x6 }, + }, + }, + { + .num_items = 8, + .items = { + { "MIC1 pin", 0x0 }, + { "MIC2 pin", 0x1 }, + { "LINE1 pin", 0x2 }, + { "LINE2 pin", 0x3 }, + { "CD pin", 0x4 }, + { "Mixer", 0x5 }, + { "LINE-OUT pin", 0x6 }, + { "HP-OUT pin", 0x7 }, + }, + }, +}; +static const struct snd_kcontrol_new alc260_test_mixer[] = { + /* Output driver widgets */ + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT), + + /* Modes for retasking pin widgets + * Note: the ALC260 doesn't seem to act on requests to enable mic + * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't + * mention this restriction. At this stage it's not clear whether + * this behaviour is intentional or is a hardware bug in chip + * revisions available at least up until early 2006. Therefore for + * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all + * choices, but if it turns out that the lack of mic bias for these + * NIDs is intentional we could change their modes from + * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. + */ + ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT), + + /* Loopback mixer controls */ + HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT), + HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT), + + /* Controls for GPIO pins, assuming they are configured as outputs */ + ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), + ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), + ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), + ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), + + /* Switches to allow the digital IO pins to be enabled. The datasheet + * is ambigious as to which NID is which; testing on laptops which + * make this output available should provide clarification. + */ + ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), + ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), + + /* A switch allowing EAPD to be enabled. Some laptops seem to use + * this output to turn on an external amplifier. + */ + ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), + ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), + + { } /* end */ +}; +static const struct hda_verb alc260_test_init_verbs[] = { + /* Enable all GPIOs as outputs with an initial value of 0 */ + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, + + /* Enable retasking pins as output, initially without power amp */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* Disable digital (SPDIF) pins initially, but users can enable + * them via a mixer switch. In the case of SPDIF-out, this initverb + * payload also sets the generation to 0, output to be in "consumer" + * PCM format, copyright asserted, no pre-emphasis and no validity + * control. + */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the + * OUT1 sum bus when acting as an output. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0c, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0e, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute retasking pin widget output buffers since the default + * state appears to be output. As the pin mode is changed by the + * user the pin mode control will take care of enabling the pin's + * input/output buffers as needed. + */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Also unmute the mono-out pin widget */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting (mic1 + * pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do the same for the second ADC: mute capture input amp and + * set ADC connection to mic1 pin + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; +#endif + +#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback +#define alc260_pcm_analog_capture alc880_pcm_analog_capture + +#define alc260_pcm_digital_playback alc880_pcm_digital_playback +#define alc260_pcm_digital_capture alc880_pcm_digital_capture + +/* + * for BIOS auto-configuration + */ + +static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, + const char *pfx, int *vol_bits) +{ + hda_nid_t nid_vol; + unsigned long vol_val, sw_val; + int err; + + if (nid >= 0x0f && nid < 0x11) { + nid_vol = nid - 0x7; + vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); + sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + } else if (nid == 0x11) { + nid_vol = nid - 0x7; + vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT); + sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); + } else if (nid >= 0x12 && nid <= 0x15) { + nid_vol = 0x08; + vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); + sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + } else + return 0; /* N/A */ + + if (!(*vol_bits & (1 << nid_vol))) { + /* first control for the volume widget */ + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val); + if (err < 0) + return err; + *vol_bits |= (1 << nid_vol); + } + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val); + if (err < 0) + return err; + return 1; +} + +/* add playback controls from the parsed DAC table */ +static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int err; + int vols = 0; + + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + spec->private_dac_nids[0] = 0x02; + + nid = cfg->line_out_pins[0]; + if (nid) { + const char *pfx; + if (!cfg->speaker_pins[0] && !cfg->hp_pins[0]) + pfx = "Master"; + else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + pfx = "Speaker"; + else + pfx = "Front"; + err = alc260_add_playback_controls(spec, nid, pfx, &vols); + if (err < 0) + return err; + } + + nid = cfg->speaker_pins[0]; + if (nid) { + err = alc260_add_playback_controls(spec, nid, "Speaker", &vols); + if (err < 0) + return err; + } + + nid = cfg->hp_pins[0]; + if (nid) { + err = alc260_add_playback_controls(spec, nid, "Headphone", + &vols); + if (err < 0) + return err; + } + return 0; +} + +/* create playback/capture controls for input pins */ +static int alc260_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05); +} + +static void alc260_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + int sel_idx) +{ + alc_set_pin_output(codec, nid, pin_type); + /* need the manual connection? */ + if (nid >= 0x12) { + int idx = nid - 0x12; + snd_hda_codec_write(codec, idx + 0x0b, 0, + AC_VERB_SET_CONNECT_SEL, sel_idx); + } +} + +static void alc260_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid; + + nid = spec->autocfg.line_out_pins[0]; + if (nid) { + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0); + } + + nid = spec->autocfg.speaker_pins[0]; + if (nid) + alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); + + nid = spec->autocfg.hp_pins[0]; + if (nid) + alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0); +} + +#define ALC260_PIN_CD_NID 0x16 +static void alc260_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (nid >= 0x12) { + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + if (nid != ALC260_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } + } +} + +#define alc260_auto_init_input_src alc880_auto_init_input_src + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc260_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for + * front panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* + * Set up output mixers (0x08 - 0x0a) + */ + /* set vol=0 to output mixers */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + { } +}; + +static int alc260_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc260_ignore[] = { 0x17, 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc260_ignore); + if (err < 0) + return err; + err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->kctls.list) + return 0; /* can't find valid BIOS pin config */ + err = alc260_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = 2; + + if (spec->autocfg.dig_outs) + spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc260_volume_init_verbs); + + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0); + + return 1; +} + +/* additional initialization for auto-configuration model */ +static void alc260_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc260_auto_init_multi_out(codec); + alc260_auto_init_analog_input(codec); + alc260_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list alc260_loopbacks[] = { + { 0x07, HDA_INPUT, 0 }, + { 0x07, HDA_INPUT, 1 }, + { 0x07, HDA_INPUT, 2 }, + { 0x07, HDA_INPUT, 3 }, + { 0x07, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + +/* + * Pin config fixes + */ +enum { + PINFIX_HP_DC5750, +}; + +static const struct alc_fixup alc260_fixups[] = { + [PINFIX_HP_DC5750] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x11, 0x90130110 }, /* speaker */ + { } + } + }, +}; + +static const struct snd_pci_quirk alc260_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750), + {} +}; + +/* + * ALC260 configurations + */ +static const char * const alc260_models[ALC260_MODEL_LAST] = { + [ALC260_BASIC] = "basic", + [ALC260_HP] = "hp", + [ALC260_HP_3013] = "hp-3013", + [ALC260_HP_DC7600] = "hp-dc7600", + [ALC260_FUJITSU_S702X] = "fujitsu", + [ALC260_ACER] = "acer", + [ALC260_WILL] = "will", + [ALC260_REPLACER_672V] = "replacer", + [ALC260_FAVORIT100] = "favorit100", +#ifdef CONFIG_SND_DEBUG + [ALC260_TEST] = "test", +#endif + [ALC260_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc260_cfg_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), + SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), + SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), + SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), + SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */ + SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), + SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), + SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP), + SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP), + SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), + SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), + SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), + SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), + {} +}; + +static const struct alc_config_preset alc260_presets[] = { + [ALC260_BASIC] = { + .mixers = { alc260_base_output_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + }, + [ALC260_HP] = { + .mixers = { alc260_hp_output_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_init_verbs, + alc260_hp_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_setup, + .init_hook = alc_inithook, + }, + [ALC260_HP_DC7600] = { + .mixers = { alc260_hp_dc7600_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_init_verbs, + alc260_hp_dc7600_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_3012_setup, + .init_hook = alc_inithook, + }, + [ALC260_HP_3013] = { + .mixers = { alc260_hp_3013_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_hp_3013_init_verbs, + alc260_hp_3013_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_3013_setup, + .init_hook = alc_inithook, + }, + [ALC260_FUJITSU_S702X] = { + .mixers = { alc260_fujitsu_mixer }, + .init_verbs = { alc260_fujitsu_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources), + .input_mux = alc260_fujitsu_capture_sources, + }, + [ALC260_ACER] = { + .mixers = { alc260_acer_mixer }, + .init_verbs = { alc260_acer_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), + .input_mux = alc260_acer_capture_sources, + }, + [ALC260_FAVORIT100] = { + .mixers = { alc260_favorit100_mixer }, + .init_verbs = { alc260_favorit100_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources), + .input_mux = alc260_favorit100_capture_sources, + }, + [ALC260_WILL] = { + .mixers = { alc260_will_mixer }, + .init_verbs = { alc260_init_verbs, alc260_will_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), + .adc_nids = alc260_adc_nids, + .dig_out_nid = ALC260_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + }, + [ALC260_REPLACER_672V] = { + .mixers = { alc260_replacer_672v_mixer }, + .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), + .adc_nids = alc260_adc_nids, + .dig_out_nid = ALC260_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc260_replacer_672v_unsol_event, + .init_hook = alc260_replacer_672v_automute, + }, +#ifdef CONFIG_SND_DEBUG + [ALC260_TEST] = { + .mixers = { alc260_test_mixer }, + .init_verbs = { alc260_test_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), + .dac_nids = alc260_test_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids), + .adc_nids = alc260_test_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources), + .input_mux = alc260_test_capture_sources, + }, +#endif +}; + +static int patch_alc260(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err, board_config; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST, + alc260_models, + alc260_cfg_tbl); + if (board_config < 0) { + snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC260_AUTO; + } + + if (board_config == ALC260_AUTO) { + alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + if (board_config == ALC260_AUTO) { + /* automatic parse from the BIOS config */ + err = alc260_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC260_BASIC; + } + } + + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + + if (board_config != ALC260_AUTO) + setup_preset(codec, &alc260_presets[board_config]); + + spec->stream_analog_playback = &alc260_pcm_analog_playback; + spec->stream_analog_capture = &alc260_pcm_analog_capture; + spec->stream_analog_alt_capture = &alc260_pcm_analog_capture; + + spec->stream_digital_playback = &alc260_pcm_digital_playback; + spec->stream_digital_capture = &alc260_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + /* check whether NID 0x04 is valid */ + unsigned int wcap = get_wcaps(codec, 0x04); + wcap = get_wcaps_type(wcap); + /* get type */ + if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { + spec->adc_nids = alc260_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); + } else { + spec->adc_nids = alc260_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); + } + } + set_capture_mixer(codec); + set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + + spec->vmaster_nid = 0x08; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC260_AUTO) + spec->init_hook = alc260_auto_init; + spec->shutup = alc_eapd_shutup; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc260_loopbacks; +#endif + + return 0; +} + + +/* + * ALC882/883/885/888/889 support + * + * ALC882 is almost identical with ALC880 but has cleaner and more flexible + * configuration. Each pin widget can choose any input DACs and a mixer. + * Each ADC is connected from a mixer of all inputs. This makes possible + * 6-channel independent captures. + * + * In addition, an independent DAC for the multi-playback (not used in this + * driver yet). + */ +#define ALC882_DIGOUT_NID 0x06 +#define ALC882_DIGIN_NID 0x0a +#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID +#define ALC883_DIGIN_NID ALC882_DIGIN_NID +#define ALC1200_DIGOUT_NID 0x10 + + +static const struct hda_channel_mode alc882_ch_modes[1] = { + { 8, NULL } +}; + +/* DACs */ +static const hda_nid_t alc882_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x03, 0x04, 0x05 +}; +#define alc883_dac_nids alc882_dac_nids + +/* ADCs */ +#define alc882_adc_nids alc880_adc_nids +#define alc882_adc_nids_alt alc880_adc_nids_alt +#define alc883_adc_nids alc882_adc_nids_alt +static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 }; +static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 }; +#define alc889_adc_nids alc880_adc_nids + +static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 }; +static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; +#define alc883_capsrc_nids alc882_capsrc_nids_alt +static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; +#define alc889_capsrc_nids alc882_capsrc_nids + +/* input MUX */ +/* FIXME: should be a matrix-type input source selection */ + +static const struct hda_input_mux alc882_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +#define alc883_capture_source alc882_capture_source + +static const struct hda_input_mux alc889_capture_source = { + .num_items = 3, + .items = { + { "Front Mic", 0x0 }, + { "Mic", 0x3 }, + { "Line", 0x2 }, + }, +}; + +static const struct hda_input_mux mb5_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x1 }, + { "Line", 0x7 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux macmini3_capture_source = { + .num_items = 2, + .items = { + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc883_3stack_6ch_intel = { + .num_items = 4, + .items = { + { "Mic", 0x1 }, + { "Front Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc883_lenovo_101e_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; + +static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + }, +}; + +static const struct hda_input_mux alc883_lenovo_sky_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x4 }, + }, +}; + +static const struct hda_input_mux alc883_asus_eee1601_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + }, +}; + +static const struct hda_input_mux alc889A_mb31_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + /* Front Mic (0x01) unused */ + { "Line", 0x2 }, + /* Line 2 (0x03) unused */ + /* CD (0x04) unused? */ + }, +}; + +static const struct hda_input_mux alc889A_imac91_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x01 }, + { "Line", 0x2 }, /* Not sure! */ + }, +}; + +/* + * 2ch mode + */ +static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = { + { 2, NULL } +}; + +/* + * 2ch mode + */ +static const struct hda_verb alc882_3ST_ch2_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc882_3ST_ch4_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc882_3ST_ch6_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = { + { 2, alc882_3ST_ch2_init }, + { 4, alc882_3ST_ch4_init }, + { 6, alc882_3ST_ch6_init }, +}; + +#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes + +/* + * 2ch mode + */ +static const struct hda_verb alc883_3ST_ch2_clevo_init[] = { + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc883_3ST_ch4_clevo_init[] = { + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc883_3ST_ch6_clevo_init[] = { + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { + { 2, alc883_3ST_ch2_clevo_init }, + { 4, alc883_3ST_ch4_clevo_init }, + { 6, alc883_3ST_ch6_clevo_init }, +}; + + +/* + * 6ch mode + */ +static const struct hda_verb alc882_sixstack_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc882_sixstack_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +static const struct hda_channel_mode alc882_sixstack_modes[2] = { + { 6, alc882_sixstack_ch6_init }, + { 8, alc882_sixstack_ch8_init }, +}; + + +/* Macbook Air 2,1 */ + +static const struct hda_channel_mode alc885_mba21_ch_modes[1] = { + { 2, NULL }, +}; + +/* + * macbook pro ALC885 can switch LineIn to LineOut without losing Mic + */ + +/* + * 2ch mode + */ +static const struct hda_verb alc885_mbp_ch2_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc885_mbp_ch4_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } /* end */ +}; + +static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = { + { 2, alc885_mbp_ch2_init }, + { 4, alc885_mbp_ch4_init }, +}; + +/* + * 2ch + * Speakers/Woofer/HP = Front + * LineIn = Input + */ +static const struct hda_verb alc885_mb5_ch2_init[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + { } /* end */ +}; + +/* + * 6ch mode + * Speakers/HP = Front + * Woofer = LFE + * LineIn = Surround + */ +static const struct hda_verb alc885_mb5_ch6_init[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + { } /* end */ +}; + +static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = { + { 2, alc885_mb5_ch2_init }, + { 6, alc885_mb5_ch6_init }, +}; + +#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes + +/* + * 2ch mode + */ +static const struct hda_verb alc883_4ST_ch2_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc883_4ST_ch4_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc883_4ST_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc883_4ST_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = { + { 2, alc883_4ST_ch2_init }, + { 4, alc883_4ST_ch4_init }, + { 6, alc883_4ST_ch6_init }, + { 8, alc883_4ST_ch8_init }, +}; + + +/* + * 2ch mode + */ +static const struct hda_verb alc883_3ST_ch2_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc883_3ST_ch4_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc883_3ST_ch6_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { + { 2, alc883_3ST_ch2_intel_init }, + { 4, alc883_3ST_ch4_intel_init }, + { 6, alc883_3ST_ch6_intel_init }, +}; + +/* + * 2ch mode + */ +static const struct hda_verb alc889_ch2_intel_init[] = { + { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc889_ch6_intel_init[] = { + { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc889_ch8_intel_init[] = { + { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ +}; + +static const struct hda_channel_mode alc889_8ch_intel_modes[3] = { + { 2, alc889_ch2_intel_init }, + { 6, alc889_ch6_intel_init }, + { 8, alc889_ch8_intel_init }, +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc883_sixstack_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc883_sixstack_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +static const struct hda_channel_mode alc883_sixstack_modes[2] = { + { 6, alc883_sixstack_ch6_init }, + { 8, alc883_sixstack_ch8_init }, +}; + + +/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 + * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b + */ +static const struct snd_kcontrol_new alc882_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +/* Macbook Air 2,1 same control for HP and internal Speaker */ + +static const struct snd_kcontrol_new alc885_mba21_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT), + { } +}; + + +static const struct snd_kcontrol_new alc885_mbp3_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_mb5_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_macmini3_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_imac91_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), + { } /* end */ +}; + + +static const struct snd_kcontrol_new alc882_w2jc_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc882_targa_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ??? + * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c + */ +static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc882_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc882_base_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* CLFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Side mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Rear Pin: output 1 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* Side Pin: output 3 (0x0f) */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + +static const struct hda_verb alc882_adc1_init_verbs[] = { + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } +}; + +static const struct hda_verb alc882_eapd_verbs[] = { + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + { } +}; + +static const struct hda_verb alc889_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc_hp15_unsol_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static const struct hda_verb alc885_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* CLFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* Side mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Front HP Pin: output 0 (0x0c) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Rear Pin: output 1 (0x0d) */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x19, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* Side Pin: output 3 (0x0f) */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* Mic (rear) pin: input vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + /* Mixer elements: 0x18, , 0x1a, 0x1b */ + /* Input mixer1 */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + { } +}; + +static const struct hda_verb alc885_init_input_verbs[] = { + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + { } +}; + + +/* Unmute Selector 24h and set the default input to front mic */ +static const struct hda_verb alc889_init_input_verbs[] = { + {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + { } +}; + + +#define alc883_init_verbs alc882_base_init_verbs + +/* Mac Pro test */ +static const struct snd_kcontrol_new alc882_macpro_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + /* FIXME: this looks suspicious... + HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT), + */ + { } /* end */ +}; + +static const struct hda_verb alc882_macpro_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin: output 0 (0x0c) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Speaker: output */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04}, + /* Headphone output (output 0 - 0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + +/* Macbook 5,1 */ +static const struct hda_verb alc885_mb5_init_verbs[] = { + /* DACs */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Front mixer */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Surround mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* LFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* HP mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin (0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* LFE Pin (0x0e) */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* HP Pin (0x0f) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)}, + { } +}; + +/* Macmini 3,1 */ +static const struct hda_verb alc885_macmini3_init_verbs[] = { + /* DACs */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Front mixer */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Surround mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* LFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* HP mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin (0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* LFE Pin (0x0e) */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* HP Pin (0x0f) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Line In pin */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + { } +}; + + +static const struct hda_verb alc885_mba21_init_verbs[] = { + /*Internal and HP Speaker Mixer*/ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /*Internal Speaker Pin (0x0c)*/ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: output 0 (0x0e) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)}, + /* Line in (is hp when jack connected)*/ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + { } + }; + + +/* Macbook Pro rev3 */ +static const struct hda_verb alc885_mbp3_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* HP mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: output 0 (0x0e) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: use output 1 when in LineOut mode */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + +/* iMac 9,1 */ +static const struct hda_verb alc885_imac91_init_verbs[] = { + /* Internal Speaker Pin (0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: Rear */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)}, + /* Line in Rear */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } +}; + +/* iMac 24 mixer. */ +static const struct snd_kcontrol_new alc885_imac24_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT), + { } /* end */ +}; + +/* iMac 24 init verbs. */ +static const struct hda_verb alc885_imac24_init_verbs[] = { + /* Internal speakers: output 0 (0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Internal speakers: output 0 (0x0c) */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Headphone: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Front Mic: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + { } +}; + +/* Toggle speaker-output according to the hp-jack state */ +static void alc885_imac24_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + spec->autocfg.speaker_pins[1] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +#define alc885_mb5_setup alc885_imac24_setup +#define alc885_macmini3_setup alc885_imac24_setup + +/* Macbook Air 2,1 */ +static void alc885_mba21_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + + + +static void alc885_mbp3_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc885_imac91_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + spec->autocfg.speaker_pins[1] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc882_targa_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc882_targa_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc_hp_automute(codec); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + spec->jack_present ? 1 : 3); +} + +static void alc882_targa_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc882_targa_automute(codec); +} + +static const struct hda_verb alc882_asus_a7j_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + { } /* end */ +}; + +static const struct hda_verb alc882_asus_a7m_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + { } /* end */ +}; + +static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) +{ + unsigned int gpiostate, gpiomask, gpiodir; + + gpiostate = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0); + + if (!muted) + gpiostate |= (1 << pin); + else + gpiostate &= ~(1 << pin); + + gpiomask = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_MASK, 0); + gpiomask |= (1 << pin); + + gpiodir = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DIRECTION, 0); + gpiodir |= (1 << pin); + + + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, gpiomask); + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, gpiodir); + + msleep(1); + + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, gpiostate); +} + +/* set up GPIO at initialization */ +static void alc885_macpro_init_hook(struct hda_codec *codec) +{ + alc882_gpio_mute(codec, 0, 0); + alc882_gpio_mute(codec, 1, 0); +} + +/* set up GPIO and update auto-muting at initialization */ +static void alc885_imac24_init_hook(struct hda_codec *codec) +{ + alc885_macpro_init_hook(codec); + alc_hp_automute(codec); +} + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc883_auto_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* + * Set up output mixers (0x0c - 0x0f) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { } +}; + +/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ +static const struct hda_verb alc889A_mb31_ch2_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ + { } /* end */ +}; + +/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ +static const struct hda_verb alc889A_mb31_ch4_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ + { } /* end */ +}; + +/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ +static const struct hda_verb alc889A_mb31_ch5_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ + { } /* end */ +}; + +/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ +static const struct hda_verb alc889A_mb31_ch6_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ + { } /* end */ +}; + +static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { + { 2, alc889A_mb31_ch2_init }, + { 4, alc889A_mb31_ch4_init }, + { 5, alc889A_mb31_ch5_init }, + { 6, alc889A_mb31_ch6_init }, +}; + +static const struct hda_verb alc883_medion_eapd_verbs[] = { + /* eanable EAPD on medion laptop */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, + { } +}; + +#define alc883_base_mixer alc882_base_mixer + +static const struct snd_kcontrol_new alc883_mitac_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_fivestack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_targa_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc883_medion_wim2160_verbs[] = { + /* Unmute front mixer */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Set speaker pin to front mixer */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Init headphone pin */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_medion_wim2160_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1a; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", + 0x0d, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc889A_mb31_mixer[] = { + /* Output mixers */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT), + /* Output switches */ + HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT), + /* Boost mixers */ + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), + /* Input mixers */ + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_vaiott_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_bind_ctls alc883_bind_cap_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc883_bind_cap_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { + HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), + HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_mitac_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc883_mitac_verbs[] = { + /* HP */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Subwoofer */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* enable unsolicited event */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */ + + { } /* end */ +}; + +static const struct hda_verb alc883_clevo_m540r_verbs[] = { + /* HP */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Int speaker */ + /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/ + + /* enable unsolicited event */ + /* + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + */ + + { } /* end */ +}; + +static const struct hda_verb alc883_clevo_m720_verbs[] = { + /* HP */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Int speaker */ + {0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* enable unsolicited event */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { + /* HP */ + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Subwoofer */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* enable unsolicited event */ + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +static const struct hda_verb alc883_targa_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + +/* Connect Line-Out side jack (SPDIF) to Side */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, +/* Connect Mic jack to CLFE */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, +/* Connect Line-in jack to Surround */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, +/* Connect HP out jack to Front */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +static const struct hda_verb alc883_lenovo_101e_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN}, + { } /* end */ +}; + +static const struct hda_verb alc883_lenovo_nb0763_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + { } /* end */ +}; + +static const struct hda_verb alc888_lenovo_ms7195_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +static const struct hda_verb alc883_haier_w66_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + { } /* end */ +}; + +static const struct hda_verb alc888_lenovo_sky_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +static const struct hda_verb alc888_6st_dell_verbs[] = { + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +static const struct hda_verb alc883_vaiott_verbs[] = { + /* HP */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + + /* enable unsolicited event */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +static void alc888_3st_hp_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x18; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc888_3st_hp_verbs[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */ + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +/* + * 2ch mode + */ +static const struct hda_verb alc888_3st_hp_2ch_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc888_3st_hp_4ch_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc888_3st_hp_6ch_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc888_3st_hp_modes[3] = { + { 2, alc888_3st_hp_2ch_init }, + { 4, alc888_3st_hp_4ch_init }, + { 6, alc888_3st_hp_6ch_init }, +}; + +static void alc888_lenovo_ms7195_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_lenovo_nb0763_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* toggle speaker-output according to the hp-jack state */ +#define alc883_targa_init_hook alc882_targa_init_hook +#define alc883_targa_unsol_event alc882_targa_unsol_event + +static void alc883_clevo_m720_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc883_clevo_m720_init_hook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc88x_simple_mic_automute(codec); +} + +static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_MIC_EVENT: + alc88x_simple_mic_automute(codec); + break; + default: + alc_sku_unsol_event(codec, res); + break; + } +} + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc883_haier_w66_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc883_lenovo_101e_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_acer_aspire_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc883_acer_eapd_verbs[] = { + /* HP Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Front Pin: output 0 (0x0c) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* eanable EAPD on medion laptop */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, + /* enable unsolicited event */ + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +static void alc888_6st_dell_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.speaker_pins[2] = 0x16; + spec->autocfg.speaker_pins[3] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc888_lenovo_sky_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.speaker_pins[2] = 0x16; + spec->autocfg.speaker_pins[3] = 0x17; + spec->autocfg.speaker_pins[4] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc883_vaiott_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc888_asus_m90v_verbs[] = { + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* enable unsolicited event */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +static void alc883_mode2_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.speaker_pins[2] = 0x16; + spec->ext_mic.pin = 0x18; + spec->int_mic.pin = 0x19; + spec->ext_mic.mux_idx = 0; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct hda_verb alc888_asus_eee1601_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0838}, + /* enable unsolicited event */ + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +static void alc883_eee1601_inithook(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + alc_hp_automute(codec); +} + +static const struct hda_verb alc889A_mb31_verbs[] = { + /* Init rear pin (used as headphone output) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Init line pin (used as output in 4ch and 6ch mode) */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */ + /* Init line 2 pin (used as headphone out by default) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */ + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */ + { } /* end */ +}; + +/* Mute speakers according to the headphone jack state */ +static void alc889A_mb31_automute(struct hda_codec *codec) +{ + unsigned int present; + + /* Mute only in 2ch or 4ch mode */ + if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0) + == 0x00) { + present = snd_hda_jack_detect(codec, 0x15); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + } +} + +static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc889A_mb31_automute(codec); +} + + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc882_loopbacks alc880_loopbacks +#endif + +/* pcm configuration: identical with ALC880 */ +#define alc882_pcm_analog_playback alc880_pcm_analog_playback +#define alc882_pcm_analog_capture alc880_pcm_analog_capture +#define alc882_pcm_digital_playback alc880_pcm_digital_playback +#define alc882_pcm_digital_capture alc880_pcm_digital_capture + +static const hda_nid_t alc883_slave_dig_outs[] = { + ALC1200_DIGOUT_NID, 0, +}; + +static const hda_nid_t alc1200_slave_dig_outs[] = { + ALC883_DIGOUT_NID, 0, +}; + +/* + * configuration and preset + */ +static const char * const alc882_models[ALC882_MODEL_LAST] = { + [ALC882_3ST_DIG] = "3stack-dig", + [ALC882_6ST_DIG] = "6stack-dig", + [ALC882_ARIMA] = "arima", + [ALC882_W2JC] = "w2jc", + [ALC882_TARGA] = "targa", + [ALC882_ASUS_A7J] = "asus-a7j", + [ALC882_ASUS_A7M] = "asus-a7m", + [ALC885_MACPRO] = "macpro", + [ALC885_MB5] = "mb5", + [ALC885_MACMINI3] = "macmini3", + [ALC885_MBA21] = "mba21", + [ALC885_MBP3] = "mbp3", + [ALC885_IMAC24] = "imac24", + [ALC885_IMAC91] = "imac91", + [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig", + [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig", + [ALC883_3ST_6ch] = "3stack-6ch", + [ALC883_6ST_DIG] = "alc883-6stack-dig", + [ALC883_TARGA_DIG] = "targa-dig", + [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", + [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig", + [ALC883_ACER] = "acer", + [ALC883_ACER_ASPIRE] = "acer-aspire", + [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", + [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g", + [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g", + [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g", + [ALC883_MEDION] = "medion", + [ALC883_MEDION_WIM2160] = "medion-wim2160", + [ALC883_LAPTOP_EAPD] = "laptop-eapd", + [ALC883_LENOVO_101E_2ch] = "lenovo-101e", + [ALC883_LENOVO_NB0763] = "lenovo-nb0763", + [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig", + [ALC888_LENOVO_SKY] = "lenovo-sky", + [ALC883_HAIER_W66] = "haier-w66", + [ALC888_3ST_HP] = "3stack-hp", + [ALC888_6ST_DELL] = "6stack-dell", + [ALC883_MITAC] = "mitac", + [ALC883_CLEVO_M540R] = "clevo-m540r", + [ALC883_CLEVO_M720] = "clevo-m720", + [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", + [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", + [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", + [ALC889A_INTEL] = "intel-alc889a", + [ALC889_INTEL] = "intel-x58", + [ALC1200_ASUS_P5Q] = "asus-p5q", + [ALC889A_MB31] = "mb31", + [ALC883_SONY_VAIO_TT] = "sony-vaio-tt", + [ALC882_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc882_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), + + SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", + ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", + ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", + ALC888_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", + ALC888_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO), + SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO), + SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", + ALC888_ACER_ASPIRE_6530G), + SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", + ALC888_ACER_ASPIRE_6530G), + SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", + ALC888_ACER_ASPIRE_7730G), + /* default Acer -- disabled as it causes more problems. + * model=auto should work fine now + */ + /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */ + + SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), + + SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP), + + SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), + SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), + SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), + SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q), + SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), + + SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT), + SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC), + SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC), + SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), + SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL), + SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), + + SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ + SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO), + SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG), + SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG), + + SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), + SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720), + SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R), + SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD), + SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), + /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */ + SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), + SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx", + ALC883_FUJITSU_PI2515), + SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx", + ALC888_FUJITSU_XA3530), + SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), + SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY), + SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG), + SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), + + SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), + SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL), + SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC), + SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL), + SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL), + SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL), + SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG), + + {} +}; + +/* codec SSID table for Intel Mac */ +static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { + SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO), + SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), + SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), + SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), + SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M), + SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21), + SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), + SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), + SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91), + SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5), + /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, + * so apparently no perfect solution yet + */ + SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3), + {} /* terminator */ +}; + +static const struct alc_config_preset alc882_presets[] = { + [ALC882_3ST_DIG] = { + .mixers = { alc882_base_mixer }, + .init_verbs = { alc882_base_init_verbs, + alc882_adc1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), + .channel_mode = alc882_ch_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, + [ALC882_6ST_DIG] = { + .mixers = { alc882_base_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, + alc882_adc1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), + .channel_mode = alc882_sixstack_modes, + .input_mux = &alc882_capture_source, + }, + [ALC882_ARIMA] = { + .mixers = { alc882_base_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc882_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), + .channel_mode = alc882_sixstack_modes, + .input_mux = &alc882_capture_source, + }, + [ALC882_W2JC] = { + .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc882_eapd_verbs, alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + }, + [ALC885_MBA21] = { + .mixers = { alc885_mba21_mixer }, + .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs }, + .num_dacs = 2, + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mba21_ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), + .input_mux = &alc882_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_mba21_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MBP3] = { + .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mbp3_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = 2, + .dac_nids = alc882_dac_nids, + .hp_nid = 0x04, + .channel_mode = alc885_mbp_4ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes), + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_mbp3_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MB5] = { + .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mb5_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mb5_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), + .input_mux = &mb5_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_mb5_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MACMINI3] = { + .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_macmini3_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_macmini3_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes), + .input_mux = &macmini3_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_macmini3_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MACPRO] = { + .mixers = { alc882_macpro_mixer }, + .init_verbs = { alc882_macpro_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), + .channel_mode = alc882_ch_modes, + .input_mux = &alc882_capture_source, + .init_hook = alc885_macpro_init_hook, + }, + [ALC885_IMAC24] = { + .mixers = { alc885_imac24_mixer }, + .init_verbs = { alc885_imac24_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), + .channel_mode = alc882_ch_modes, + .input_mux = &alc882_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_imac24_setup, + .init_hook = alc885_imac24_init_hook, + }, + [ALC885_IMAC91] = { + .mixers = {alc885_imac91_mixer}, + .init_verbs = { alc885_imac91_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mba21_ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), + .input_mux = &alc889A_imac91_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_imac91_setup, + .init_hook = alc_hp_automute, + }, + [ALC882_TARGA] = { + .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc880_gpio3_init_verbs, alc882_targa_verbs}, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), + .adc_nids = alc882_adc_nids, + .capsrc_nids = alc882_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), + .channel_mode = alc882_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, + }, + [ALC882_ASUS_A7J] = { + .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc882_asus_a7j_verbs}, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), + .adc_nids = alc882_adc_nids, + .capsrc_nids = alc882_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), + .channel_mode = alc882_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, + [ALC882_ASUS_A7M] = { + .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc882_eapd_verbs, alc880_gpio1_init_verbs, + alc882_asus_a7m_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, + [ALC883_3ST_2ch_DIG] = { + .mixers = { alc883_3ST_2ch_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + }, + [ALC883_3ST_6ch_DIG] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + }, + [ALC883_3ST_6ch] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + }, + [ALC883_3ST_6ch_INTEL] = { + .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc883_slave_dig_outs, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes), + .channel_mode = alc883_3ST_6ch_intel_modes, + .need_dac_fix = 1, + .input_mux = &alc883_3stack_6ch_intel, + }, + [ALC889A_INTEL] = { + .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, + .init_verbs = { alc885_init_verbs, alc885_init_input_verbs, + alc_hp15_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), + .adc_nids = alc889_adc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc883_slave_dig_outs, + .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes), + .channel_mode = alc889_8ch_intel_modes, + .capsrc_nids = alc889_capsrc_nids, + .input_mux = &alc889_capture_source, + .setup = alc889_automute_setup, + .init_hook = alc_hp_automute, + .unsol_event = alc_sku_unsol_event, + .need_dac_fix = 1, + }, + [ALC889_INTEL] = { + .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, + .init_verbs = { alc885_init_verbs, alc889_init_input_verbs, + alc889_eapd_verbs, alc_hp15_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), + .adc_nids = alc889_adc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc883_slave_dig_outs, + .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes), + .channel_mode = alc889_8ch_intel_modes, + .capsrc_nids = alc889_capsrc_nids, + .input_mux = &alc889_capture_source, + .setup = alc889_automute_setup, + .init_hook = alc889_intel_init_hook, + .unsol_event = alc_sku_unsol_event, + .need_dac_fix = 1, + }, + [ALC883_6ST_DIG] = { + .mixers = { alc883_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + }, + [ALC883_TARGA_DIG] = { + .mixers = { alc883_targa_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, + alc883_targa_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_targa_unsol_event, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, + }, + [ALC883_TARGA_2ch_DIG] = { + .mixers = { alc883_targa_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, + alc883_targa_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_targa_unsol_event, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, + }, + [ALC883_TARGA_8ch_DIG] = { + .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, + alc883_targa_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes), + .channel_mode = alc883_4ST_8ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_targa_unsol_event, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, + }, + [ALC883_ACER] = { + .mixers = { alc883_base_mixer }, + /* On TravelMate laptops, GPIO 0 enables the internal speaker + * and the headphone jack. Turn this on and rely on the + * standard mute methods whenever the user wants to turn + * these outputs off. + */ + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + }, + [ALC883_ACER_ASPIRE] = { + .mixers = { alc883_acer_aspire_mixer }, + .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_acer_aspire_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_ACER_ASPIRE_4930G] = { + .mixers = { alc888_acer_aspire_4930g_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc888_acer_aspire_4930g_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .const_channel_count = 6, + .num_mux_defs = + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_2_capture_sources, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_acer_aspire_4930g_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_ACER_ASPIRE_6530G] = { + .mixers = { alc888_acer_aspire_6530_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc888_acer_aspire_6530g_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .num_mux_defs = + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_acer_aspire_6530_sources, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_acer_aspire_6530g_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_ACER_ASPIRE_8930G] = { + .mixers = { alc889_acer_aspire_8930g_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc889_acer_aspire_8930g_verbs, + alc889_eapd_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), + .adc_nids = alc889_adc_nids, + .capsrc_nids = alc889_capsrc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .const_channel_count = 6, + .num_mux_defs = + ARRAY_SIZE(alc889_capture_sources), + .input_mux = alc889_capture_sources, + .unsol_event = alc_sku_unsol_event, + .setup = alc889_acer_aspire_8930g_setup, + .init_hook = alc_hp_automute, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .power_hook = alc_power_eapd, +#endif + }, + [ALC888_ACER_ASPIRE_7730G] = { + .mixers = { alc883_3ST_6ch_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc888_acer_aspire_7730G_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .const_channel_count = 6, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_acer_aspire_7730g_setup, + .init_hook = alc_hp_automute, + }, + [ALC883_MEDION] = { + .mixers = { alc883_fivestack_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, + alc883_medion_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + }, + [ALC883_MEDION_WIM2160] = { + .mixers = { alc883_medion_wim2160_mixer }, + .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_medion_wim2160_setup, + .init_hook = alc_hp_automute, + }, + [ALC883_LAPTOP_EAPD] = { + .mixers = { alc883_base_mixer }, + .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + }, + [ALC883_CLEVO_M540R] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes), + .channel_mode = alc883_3ST_6ch_clevo_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + /* This machine has the hardware HP auto-muting, thus + * we need no software mute via unsol event + */ + }, + [ALC883_CLEVO_M720] = { + .mixers = { alc883_clevo_m720_mixer }, + .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_clevo_m720_unsol_event, + .setup = alc883_clevo_m720_setup, + .init_hook = alc883_clevo_m720_init_hook, + }, + [ALC883_LENOVO_101E_2ch] = { + .mixers = { alc883_lenovo_101e_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_lenovo_101e_capture_source, + .setup = alc883_lenovo_101e_setup, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc_inithook, + }, + [ALC883_LENOVO_NB0763] = { + .mixers = { alc883_lenovo_nb0763_mixer }, + .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_lenovo_nb0763_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_lenovo_nb0763_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_LENOVO_MS7195_DIG] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_lenovo_ms7195_setup, + .init_hook = alc_inithook, + }, + [ALC883_HAIER_W66] = { + .mixers = { alc883_targa_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_haier_w66_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_3ST_HP] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes), + .channel_mode = alc888_3st_hp_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_3st_hp_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_6ST_DELL] = { + .mixers = { alc883_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_6st_dell_setup, + .init_hook = alc_hp_automute, + }, + [ALC883_MITAC] = { + .mixers = { alc883_mitac_mixer }, + .init_verbs = { alc883_init_verbs, alc883_mitac_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_mitac_setup, + .init_hook = alc_hp_automute, + }, + [ALC883_FUJITSU_PI2515] = { + .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, + .init_verbs = { alc883_init_verbs, + alc883_2ch_fujitsu_pi2515_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_fujitsu_pi2515_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_2ch_fujitsu_pi2515_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_FUJITSU_XA3530] = { + .mixers = { alc888_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, + alc888_fujitsu_xa3530_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes), + .channel_mode = alc888_4ST_8ch_intel_modes, + .num_mux_defs = + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_2_capture_sources, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_fujitsu_xa3530_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_LENOVO_SKY] = { + .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .need_dac_fix = 1, + .input_mux = &alc883_lenovo_sky_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_lenovo_sky_setup, + .init_hook = alc_hp_automute, + }, + [ALC888_ASUS_M90V] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_fujitsu_pi2515_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_mode2_setup, + .init_hook = alc_inithook, + }, + [ALC888_ASUS_EEE1601] = { + .mixers = { alc883_asus_eee1601_mixer }, + .cap_mixer = alc883_asus_eee1601_cap_mixer, + .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_asus_eee1601_capture_source, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc883_eee1601_inithook, + }, + [ALC1200_ASUS_P5Q] = { + .mixers = { alc883_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC1200_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc1200_slave_dig_outs, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + }, + [ALC889A_MB31] = { + .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer}, + .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs, + alc880_gpio1_init_verbs }, + .adc_nids = alc883_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .capsrc_nids = alc883_capsrc_nids, + .dac_nids = alc883_dac_nids, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .channel_mode = alc889A_mb31_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes), + .input_mux = &alc889A_mb31_capture_source, + .dig_out_nid = ALC883_DIGOUT_NID, + .unsol_event = alc889A_mb31_unsol_event, + .init_hook = alc889A_mb31_automute, + }, + [ALC883_SONY_VAIO_TT] = { + .mixers = { alc883_vaiott_mixer }, + .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_vaiott_setup, + .init_hook = alc_hp_automute, + }, +}; + + +/* + * Pin config fixes + */ +enum { + PINFIX_ABIT_AW9D_MAX, + PINFIX_LENOVO_Y530, + PINFIX_PB_M5210, + PINFIX_ACER_ASPIRE_7736, +}; + +static const struct alc_fixup alc882_fixups[] = { + [PINFIX_ABIT_AW9D_MAX] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x15, 0x01080104 }, /* side */ + { 0x16, 0x01011012 }, /* rear */ + { 0x17, 0x01016011 }, /* clfe */ + { } + } + }, + [PINFIX_LENOVO_Y530] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x15, 0x99130112 }, /* rear int speakers */ + { 0x16, 0x99130111 }, /* subwoofer */ + { } + } + }, + [PINFIX_PB_M5210] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + {} + } + }, + [PINFIX_ACER_ASPIRE_7736] = { + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, + }, +}; + +static const struct snd_pci_quirk alc882_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), + SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530), + SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), + SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736), + {} +}; + +/* + * BIOS auto configuration + */ +static int alc882_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22); +} + +static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + hda_nid_t dac) +{ + int idx; + + /* set as output */ + alc_set_pin_output(codec, nid, pin_type); + + if (dac == 0x25) + idx = 4; + else if (dac >= 0x02 && dac <= 0x05) + idx = dac - 2; + else + return; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); +} + +static void alc882_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i <= HDA_SIDE; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + if (nid) + alc882_auto_set_output_and_unmute(codec, nid, pin_type, + spec->multiout.dac_nids[i]); + } +} + +static void alc882_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin, dac; + int i; + + if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) { + for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { + pin = spec->autocfg.hp_pins[i]; + if (!pin) + break; + dac = spec->multiout.hp_nid; + if (!dac) + dac = spec->multiout.dac_nids[0]; /* to front */ + alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); + } + } + + if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) { + for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { + pin = spec->autocfg.speaker_pins[i]; + if (!pin) + break; + dac = spec->multiout.extra_out_nid[0]; + if (!dac) + dac = spec->multiout.dac_nids[0]; /* to front */ + alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); + } + } +} + +static void alc882_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } +} + +static void alc882_auto_init_input_src(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int c; + + for (c = 0; c < spec->num_adc_nids; c++) { + hda_nid_t conn_list[HDA_MAX_NUM_INPUTS]; + hda_nid_t nid = spec->capsrc_nids[c]; + unsigned int mux_idx; + const struct hda_input_mux *imux; + int conns, mute, idx, item; + + /* mute ADC */ + snd_hda_codec_write(codec, spec->adc_nids[c], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(0)); + + conns = snd_hda_get_connections(codec, nid, conn_list, + ARRAY_SIZE(conn_list)); + if (conns < 0) + continue; + mux_idx = c >= spec->num_mux_defs ? 0 : c; + imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; + for (idx = 0; idx < conns; idx++) { + /* if the current connection is the selected one, + * unmute it as default - otherwise mute it + */ + mute = AMP_IN_MUTE(idx); + for (item = 0; item < imux->num_items; item++) { + if (imux->items[item].index == idx) { + if (spec->cur_mux[c] == item) + mute = AMP_IN_UNMUTE(idx); + break; + } + } + /* check if we have a selector or mixer + * we could check for the widget type instead, but + * just check for Amp-In presence (in case of mixer + * without amp-in there is something wrong, this + * function shouldn't be used or capsrc nid is wrong) + */ + if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + mute); + else if (mute != AMP_IN_MUTE(idx)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + idx); + } + } +} + +/* add mic boosts if needed */ +static int alc_auto_add_mic_boost(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, err; + int type_idx = 0; + hda_nid_t nid; + const char *prev_label = NULL; + + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type > AUTO_PIN_MIC) + break; + nid = cfg->inputs[i].pin; + if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { + const char *label; + char boost_label[32]; + + label = hda_get_autocfg_input_label(codec, cfg, i); + if (prev_label && !strcmp(label, prev_label)) + type_idx++; + else + type_idx = 0; + prev_label = label; + + snprintf(boost_label, sizeof(boost_label), + "%s Boost Volume", label); + err = add_control(spec, ALC_CTL_WIDGET_VOL, + boost_label, type_idx, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } + } + return 0; +} + +/* almost identical with ALC880 parser... */ +static int alc882_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + static const hda_nid_t alc882_ignore[] = { 0x1d, 0 }; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc882_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) + return 0; /* can't find valid BIOS pin config */ + + err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; + err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], + "Headphone"); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, + spec->autocfg.speaker_pins[0], + "Speaker"); + if (err < 0) + return err; + err = alc882_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + alc_auto_parse_digital(codec); + + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc883_auto_init_verbs); + /* if ADC 0x07 is available, initialize it, too */ + if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN) + add_verb(spec, alc882_adc1_init_verbs); + + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + return 1; /* config found */ +} + +/* additional initialization for auto-configuration model */ +static void alc882_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc882_auto_init_multi_out(codec); + alc882_auto_init_hp_out(codec); + alc882_auto_init_analog_input(codec); + alc882_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +static int patch_alc882(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err, board_config; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + switch (codec->vendor_id) { + case 0x10ec0882: + case 0x10ec0885: + break; + default: + /* ALC883 and variants */ + alc_fix_pll_init(codec, 0x20, 0x0a, 10); + break; + } + + board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST, + alc882_models, + alc882_cfg_tbl); + + if (board_config < 0 || board_config >= ALC882_MODEL_LAST) + board_config = snd_hda_check_board_codec_sid_config(codec, + ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl); + + if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC882_AUTO; + } + + if (board_config == ALC882_AUTO) { + alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + alc_auto_parse_customize_define(codec); + + if (board_config == ALC882_AUTO) { + /* automatic parse from the BIOS config */ + err = alc882_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC882_3ST_DIG; + } + } + + if (has_cdefine_beep(codec)) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + } + + if (board_config != ALC882_AUTO) + setup_preset(codec, &alc882_presets[board_config]); + + spec->stream_analog_playback = &alc882_pcm_analog_playback; + spec->stream_analog_capture = &alc882_pcm_analog_capture; + /* FIXME: setup DAC5 */ + /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ + spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; + + spec->stream_digital_playback = &alc882_pcm_digital_playback; + spec->stream_digital_capture = &alc882_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + int i, j; + spec->num_adc_nids = 0; + for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) { + const struct hda_input_mux *imux = spec->input_mux; + hda_nid_t cap; + hda_nid_t items[16]; + hda_nid_t nid = alc882_adc_nids[i]; + unsigned int wcap = get_wcaps(codec, nid); + /* get type */ + wcap = get_wcaps_type(wcap); + if (wcap != AC_WID_AUD_IN) + continue; + spec->private_adc_nids[spec->num_adc_nids] = nid; + err = snd_hda_get_connections(codec, nid, &cap, 1); + if (err < 0) + continue; + err = snd_hda_get_connections(codec, cap, items, + ARRAY_SIZE(items)); + if (err < 0) + continue; + for (j = 0; j < imux->num_items; j++) + if (imux->items[j].index >= err) + break; + if (j < imux->num_items) + continue; + spec->private_capsrc_nids[spec->num_adc_nids] = cap; + spec->num_adc_nids++; + } + spec->adc_nids = spec->private_adc_nids; + spec->capsrc_nids = spec->private_capsrc_nids; + } + + set_capture_mixer(codec); + + if (has_cdefine_beep(codec)) + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + + spec->vmaster_nid = 0x0c; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC882_AUTO) + spec->init_hook = alc882_auto_init; + + alc_init_jacks(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc882_loopbacks; +#endif + + return 0; +} + + +/* + * ALC262 support + */ + +#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID +#define ALC262_DIGIN_NID ALC880_DIGIN_NID + +#define alc262_dac_nids alc260_dac_nids +#define alc262_adc_nids alc882_adc_nids +#define alc262_adc_nids_alt alc882_adc_nids_alt +#define alc262_capsrc_nids alc882_capsrc_nids +#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt + +#define alc262_modes alc260_modes +#define alc262_capture_source alc882_capture_source + +static const hda_nid_t alc262_dmic_adc_nids[1] = { + /* ADC0 */ + 0x09 +}; + +static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 }; + +static const struct snd_kcontrol_new alc262_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +/* update HP, line and mono-out pins according to the master switch */ +#define alc262_hp_master_update alc260_hp_master_update + +static void alc262_hp_bpc_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static void alc262_hp_wildwest_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +#define alc262_hp_master_sw_get alc260_hp_master_sw_get +#define alc262_hp_master_sw_put alc260_hp_master_sw_put + +#define ALC262_HP_MASTER_SWITCH \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Switch", \ + .info = snd_ctl_boolean_mono_info, \ + .get = alc262_hp_master_sw_get, \ + .put = alc262_hp_master_sw_put, \ + }, \ + { \ + .iface = NID_MAPPING, \ + .name = "Master Playback Switch", \ + .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \ + } + + +static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { + ALC262_HP_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { + ALC262_HP_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { + HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_hp_t5735_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_hp_t5735_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_hp_rp5700_verbs[] = { + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, + {} +}; + +static const struct hda_input_mux alc262_hp_rp5700_capture_source = { + .num_items = 1, + .items = { + { "Line", 0x1 }, + }, +}; + +/* bind hp and internal speaker mute (with plug check) as master switch */ +#define alc262_hippo_master_update alc262_hp_master_update +#define alc262_hippo_master_sw_get alc262_hp_master_sw_get +#define alc262_hippo_master_sw_put alc262_hp_master_sw_put + +#define ALC262_HIPPO_MASTER_SWITCH \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Switch", \ + .info = snd_ctl_boolean_mono_info, \ + .get = alc262_hippo_master_sw_get, \ + .put = alc262_hippo_master_sw_put, \ + }, \ + { \ + .iface = NID_MAPPING, \ + .name = "Master Playback Switch", \ + .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \ + (SUBDEV_SPEAKER(0) << 16), \ + } + +static const struct snd_kcontrol_new alc262_hippo_mixer[] = { + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_hippo1_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_hippo_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc262_hippo1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + + +static const struct snd_kcontrol_new alc262_sony_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_tyan_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_tyan_verbs[] = { + /* Headphone automute */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* P11 AUX_IN, white 4-pin connector */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1}, + {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93}, + {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19}, + + {} +}; + +/* unsolicited event for HP jack sensing */ +static void alc262_tyan_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + + +#define alc262_capture_mixer alc882_capture_mixer +#define alc262_capture_alt_mixer alc882_capture_alt_mixer + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc262_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for + * front panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + + { } +}; + +static const struct hda_verb alc262_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc262_hippo1_unsol_verbs[] = { + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static const struct hda_verb alc262_sony_unsol_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic + + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_toshiba_s06_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x09}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static void alc262_toshiba_s06_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +/* + * nec model + * 0x15 = headphone + * 0x16 = internal speaker + * 0x18 = external mic + */ + +static const struct snd_kcontrol_new alc262_nec_mixer[] = { + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_nec_verbs[] = { + /* Unmute Speaker */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Headphone */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* External mic to headphone */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* External mic to speaker */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {} +}; + +/* + * fujitsu model + * 0x14 = headphone/spdif-out, 0x15 = internal speaker, + * 0x1b = port replicator headphone out + */ + +#define ALC_HP_EVENT ALC880_HP_EVENT + +static const struct hda_verb alc262_fujitsu_unsol_verbs[] = { + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = { + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static const struct hda_verb alc262_lenovo_3000_init_verbs[] = { + /* Front Mic pin: input vref at 50% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {} +}; + +static const struct hda_input_mux alc262_fujitsu_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc262_HP_capture_source = { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "AUX IN", 0x6 }, + }, +}; + +static const struct hda_input_mux alc262_HP_D7000_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x2 }, + { "Line", 0x1 }, + { "CD", 0x4 }, + }, +}; + +static void alc262_fujitsu_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.hp_pins[1] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* bind volumes of both NID 0x0c and 0x0d */ +static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, + }, + { + .iface = NID_MAPPING, + .name = "Master Playback Switch", + .private_value = 0x1b, + }, + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static void alc262_lenovo_3000_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, + }, + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +/* additional init verbs for Benq laptops */ +static const struct hda_verb alc262_EAPD_verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, + {} +}; + +static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, + {} +}; + +/* Samsung Q1 Ultra Vista model setup */ +static const struct snd_kcontrol_new alc262_ultra_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_ultra_verbs[] = { + /* output mixer */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* speaker */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + /* internal mic */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* ADC, choose mic */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)}, + {} +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_ultra_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + + mute = 0; + /* auto-mute only when HP is used as HP */ + if (!spec->cur_mux[0]) { + spec->jack_present = snd_hda_jack_detect(codec, 0x15); + if (spec->jack_present) + mute = HDA_AMP_MUTE; + } + /* mute/unmute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + /* mute/unmute HP */ + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE); +} + +/* unsolicited event for HP jack sensing */ +static void alc262_ultra_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_ultra_automute(codec); +} + +static const struct hda_input_mux alc262_ultra_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "Headphone", 0x7 }, + }, +}; + +static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int ret; + + ret = alc_mux_enum_put(kcontrol, ucontrol); + if (!ret) + return 0; + /* reprogram the HP pin as mic or HP according to the input source */ + snd_hda_codec_write_cache(codec, 0x15, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->cur_mux[0] ? PIN_VREF80 : PIN_HP); + alc262_ultra_automute(codec); /* mute/unmute HP */ + return ret; +} + +static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc262_ultra_mux_enum_put, + }, + { + .iface = NID_MAPPING, + .name = "Capture Source", + .private_value = 0x15, + }, + { } /* end */ +}; + +/* We use two mixers depending on the output pin; 0x16 is a mono output + * and thus it's bound with a different mixer. + * This function returns which mixer amp should be used. + */ +static int alc262_check_volbit(hda_nid_t nid) +{ + if (!nid) + return 0; + else if (nid == 0x16) + return 2; + else + return 1; +} + +static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid, + const char *pfx, int *vbits, int idx) +{ + unsigned long val; + int vbit; + + vbit = alc262_check_volbit(nid); + if (!vbit) + return 0; + if (*vbits & vbit) /* a volume control for this mixer already there */ + return 0; + *vbits |= vbit; + if (vbit == 2) + val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT); + else + val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT); + return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val); +} + +static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid, + const char *pfx, int idx) +{ + unsigned long val; + + if (!nid) + return 0; + if (nid == 0x16) + val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); + else + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val); +} + +/* add playback controls from the parsed DAC table */ +static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + const char *pfx; + int vbits; + int i, err; + + spec->multiout.num_dacs = 1; /* only use one dac */ + spec->multiout.dac_nids = spec->private_dac_nids; + spec->private_dac_nids[0] = 2; + + pfx = alc_get_line_out_pfx(spec, true); + if (!pfx) + pfx = "Front"; + for (i = 0; i < 2; i++) { + err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i); + if (err < 0) + return err; + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i], + "Speaker", i); + if (err < 0) + return err; + } + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i], + "Headphone", i); + if (err < 0) + return err; + } + } + + vbits = alc262_check_volbit(cfg->line_out_pins[0]) | + alc262_check_volbit(cfg->speaker_pins[0]) | + alc262_check_volbit(cfg->hp_pins[0]); + if (vbits == 1 || vbits == 2) + pfx = "Master"; /* only one mixer is used */ + vbits = 0; + for (i = 0; i < 2; i++) { + err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx, + &vbits, i); + if (err < 0) + return err; + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i], + "Speaker", &vbits, i); + if (err < 0) + return err; + } + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i], + "Headphone", &vbits, i); + if (err < 0) + return err; + } + } + return 0; +} + +#define alc262_auto_create_input_ctls \ + alc882_auto_create_input_ctls + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc262_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for + * front panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* + * Set up output mixers (0x0c - 0x0f) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + + { } +}; + +static const struct hda_verb alc262_HP_BPC_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for + * front panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */ + /* Input mixer1: only unmute Mic */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } +}; + +static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for front + * panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */ + + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/ + /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, + + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } +}; + +static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) }, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) }, + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +/* + * Pin config fixes + */ +enum { + PINFIX_FSC_H270, + PINFIX_HP_Z200, +}; + +static const struct alc_fixup alc262_fixups[] = { + [PINFIX_FSC_H270] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x15, 0x0221142f }, /* front HP */ + { 0x1b, 0x0121141f }, /* rear HP */ + { } + } + }, + [PINFIX_HP_Z200] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x16, 0x99130120 }, /* internal speaker */ + { } + } + }, +}; + +static const struct snd_pci_quirk alc262_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200), + SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270), + {} +}; + + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc262_loopbacks alc880_loopbacks +#endif + +/* pcm configuration: identical with ALC880 */ +#define alc262_pcm_analog_playback alc880_pcm_analog_playback +#define alc262_pcm_analog_capture alc880_pcm_analog_capture +#define alc262_pcm_digital_playback alc880_pcm_digital_playback +#define alc262_pcm_digital_capture alc880_pcm_digital_capture + +/* + * BIOS auto configuration + */ +static int alc262_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc262_ignore[] = { 0x1d, 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc262_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) { + if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } + return 0; /* can't find valid BIOS pin config */ + } + err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc262_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + dig_only: + alc_auto_parse_digital(codec); + + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc262_volume_init_verbs); + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + return 1; +} + +#define alc262_auto_init_multi_out alc882_auto_init_multi_out +#define alc262_auto_init_hp_out alc882_auto_init_hp_out +#define alc262_auto_init_analog_input alc882_auto_init_analog_input +#define alc262_auto_init_input_src alc882_auto_init_input_src + + +/* init callback for auto-configuration model -- overriding the default init */ +static void alc262_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc262_auto_init_multi_out(codec); + alc262_auto_init_hp_out(codec); + alc262_auto_init_analog_input(codec); + alc262_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +/* + * configuration and preset + */ +static const char * const alc262_models[ALC262_MODEL_LAST] = { + [ALC262_BASIC] = "basic", + [ALC262_HIPPO] = "hippo", + [ALC262_HIPPO_1] = "hippo_1", + [ALC262_FUJITSU] = "fujitsu", + [ALC262_HP_BPC] = "hp-bpc", + [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", + [ALC262_HP_TC_T5735] = "hp-tc-t5735", + [ALC262_HP_RP5700] = "hp-rp5700", + [ALC262_BENQ_ED8] = "benq", + [ALC262_BENQ_T31] = "benq-t31", + [ALC262_SONY_ASSAMD] = "sony-assamd", + [ALC262_TOSHIBA_S06] = "toshiba-s06", + [ALC262_TOSHIBA_RX1] = "toshiba-rx1", + [ALC262_ULTRA] = "ultra", + [ALC262_LENOVO_3000] = "lenovo-3000", + [ALC262_NEC] = "nec", + [ALC262_TYAN] = "tyan", + [ALC262_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc262_cfg_tbl[] = { + SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), + SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series", + ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", + ALC262_AUTO), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735", + ALC262_HP_TC_T5735), + SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700), + SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), + SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ + SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), + SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO), + SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO), +#if 0 /* disable the quirk since model=auto works better in recent versions */ + SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", + ALC262_SONY_ASSAMD), +#endif + SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", + ALC262_TOSHIBA_RX1), + SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), + SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), + SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), + SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN), + SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1", + ALC262_ULTRA), + SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO), + SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000), + SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), + SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), + SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), + {} +}; + +static const struct alc_config_preset alc262_presets[] = { + [ALC262_BASIC] = { + .mixers = { alc262_base_mixer }, + .init_verbs = { alc262_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + }, + [ALC262_HIPPO] = { + .mixers = { alc262_hippo_mixer }, + .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo_setup, + .init_hook = alc_inithook, + }, + [ALC262_HIPPO_1] = { + .mixers = { alc262_hippo1_mixer }, + .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x02, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo1_setup, + .init_hook = alc_inithook, + }, + [ALC262_FUJITSU] = { + .mixers = { alc262_fujitsu_mixer }, + .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, + alc262_fujitsu_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_fujitsu_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_fujitsu_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_BPC] = { + .mixers = { alc262_HP_BPC_mixer }, + .init_verbs = { alc262_HP_BPC_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_bpc_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_BPC_D7000_WF] = { + .mixers = { alc262_HP_BPC_WildWest_mixer }, + .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_D7000_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_wildwest_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_BPC_D7000_WL] = { + .mixers = { alc262_HP_BPC_WildWest_mixer, + alc262_HP_BPC_WildWest_option_mixer }, + .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_D7000_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_wildwest_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_TC_T5735] = { + .mixers = { alc262_hp_t5735_mixer }, + .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_t5735_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_RP5700] = { + .mixers = { alc262_hp_rp5700_mixer }, + .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_hp_rp5700_capture_source, + }, + [ALC262_BENQ_ED8] = { + .mixers = { alc262_base_mixer }, + .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + }, + [ALC262_SONY_ASSAMD] = { + .mixers = { alc262_sony_mixer }, + .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo_setup, + .init_hook = alc_inithook, + }, + [ALC262_BENQ_T31] = { + .mixers = { alc262_benq_t31_mixer }, + .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, + alc_hp15_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo_setup, + .init_hook = alc_inithook, + }, + [ALC262_ULTRA] = { + .mixers = { alc262_ultra_mixer }, + .cap_mixer = alc262_ultra_capture_mixer, + .init_verbs = { alc262_ultra_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_ultra_capture_source, + .adc_nids = alc262_adc_nids, /* ADC0 */ + .capsrc_nids = alc262_capsrc_nids, + .num_adc_nids = 1, /* single ADC */ + .unsol_event = alc262_ultra_unsol_event, + .init_hook = alc262_ultra_automute, + }, + [ALC262_LENOVO_3000] = { + .mixers = { alc262_lenovo_3000_mixer }, + .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, + alc262_lenovo_3000_unsol_verbs, + alc262_lenovo_3000_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_fujitsu_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_lenovo_3000_setup, + .init_hook = alc_inithook, + }, + [ALC262_NEC] = { + .mixers = { alc262_nec_mixer }, + .init_verbs = { alc262_nec_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + }, + [ALC262_TOSHIBA_S06] = { + .mixers = { alc262_toshiba_s06_mixer }, + .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs, + alc262_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .capsrc_nids = alc262_dmic_capsrc_nids, + .dac_nids = alc262_dac_nids, + .adc_nids = alc262_dmic_adc_nids, /* ADC0 */ + .num_adc_nids = 1, /* single ADC */ + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_toshiba_s06_setup, + .init_hook = alc_inithook, + }, + [ALC262_TOSHIBA_RX1] = { + .mixers = { alc262_toshiba_rx1_mixer }, + .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo_setup, + .init_hook = alc_inithook, + }, + [ALC262_TYAN] = { + .mixers = { alc262_tyan_mixer }, + .init_verbs = { alc262_init_verbs, alc262_tyan_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x02, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_tyan_setup, + .init_hook = alc_hp_automute, + }, +}; + +static int patch_alc262(struct hda_codec *codec) +{ + struct alc_spec *spec; + int board_config; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; +#if 0 + /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is + * under-run + */ + { + int tmp; + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); + tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); + } +#endif + alc_auto_parse_customize_define(codec); + + alc_fix_pll_init(codec, 0x20, 0x0a, 10); + + board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, + alc262_models, + alc262_cfg_tbl); + + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC262_AUTO; + } + + if (board_config == ALC262_AUTO) { + alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + if (board_config == ALC262_AUTO) { + /* automatic parse from the BIOS config */ + err = alc262_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC262_BASIC; + } + } + + if (!spec->no_analog && has_cdefine_beep(codec)) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + } + + if (board_config != ALC262_AUTO) + setup_preset(codec, &alc262_presets[board_config]); + + spec->stream_analog_playback = &alc262_pcm_analog_playback; + spec->stream_analog_capture = &alc262_pcm_analog_capture; + + spec->stream_digital_playback = &alc262_pcm_digital_playback; + spec->stream_digital_capture = &alc262_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + int i; + /* check whether the digital-mic has to be supported */ + for (i = 0; i < spec->input_mux->num_items; i++) { + if (spec->input_mux->items[i].index >= 9) + break; + } + if (i < spec->input_mux->num_items) { + /* use only ADC0 */ + spec->adc_nids = alc262_dmic_adc_nids; + spec->num_adc_nids = 1; + spec->capsrc_nids = alc262_dmic_capsrc_nids; + } else { + /* all analog inputs */ + /* check whether NID 0x07 is valid */ + unsigned int wcap = get_wcaps(codec, 0x07); + + /* get type */ + wcap = get_wcaps_type(wcap); + if (wcap != AC_WID_AUD_IN) { + spec->adc_nids = alc262_adc_nids_alt; + spec->num_adc_nids = + ARRAY_SIZE(alc262_adc_nids_alt); + spec->capsrc_nids = alc262_capsrc_nids_alt; + } else { + spec->adc_nids = alc262_adc_nids; + spec->num_adc_nids = + ARRAY_SIZE(alc262_adc_nids); + spec->capsrc_nids = alc262_capsrc_nids; + } + } + } + if (!spec->cap_mixer && !spec->no_analog) + set_capture_mixer(codec); + if (!spec->no_analog && has_cdefine_beep(codec)) + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + + spec->vmaster_nid = 0x0c; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC262_AUTO) + spec->init_hook = alc262_auto_init; + spec->shutup = alc_eapd_shutup; + + alc_init_jacks(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc262_loopbacks; +#endif + + return 0; +} + +/* + * ALC268 channel source setting (2 channel) + */ +#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID +#define alc268_modes alc260_modes + +static const hda_nid_t alc268_dac_nids[2] = { + /* front, hp */ + 0x02, 0x03 +}; + +static const hda_nid_t alc268_adc_nids[2] = { + /* ADC0-1 */ + 0x08, 0x07 +}; + +static const hda_nid_t alc268_adc_nids_alt[1] = { + /* ADC0 */ + 0x08 +}; + +static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 }; + +static const struct snd_kcontrol_new alc268_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc268_toshiba_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +/* bind Beep switches of both NID 0x0f and 0x10 */ +static const struct hda_bind_ctls alc268_bind_beep_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc268_beep_mixer[] = { + HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT), + HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw), + { } +}; + +static const struct hda_verb alc268_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +/* Toshiba specific */ +static const struct hda_verb alc268_toshiba_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +/* Acer specific */ +/* bind volumes of both NID 0x02 and 0x03 */ +static const struct hda_bind_ctls alc268_acer_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static void alc268_acer_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +#define alc268_acer_master_sw_get alc262_hp_master_sw_get +#define alc268_acer_master_sw_put alc262_hp_master_sw_put + +static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x15, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, + .put = alc268_acer_master_sw_put, + }, + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc268_acer_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, + .put = alc268_acer_master_sw_put, + }, + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, + .put = alc268_acer_master_sw_put, + }, + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +static const struct hda_verb alc268_acer_aspire_one_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x23, AC_VERB_SET_CONNECT_SEL, 0x06}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017}, + { } +}; + +static const struct hda_verb alc268_acer_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +/* unsolicited event for HP jack sensing */ +#define alc268_toshiba_setup alc262_hippo_setup + +static void alc268_acer_lc_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 6; + spec->auto_mic = 1; +} + +static const struct snd_kcontrol_new alc268_dell_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct hda_verb alc268_dell_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + { } +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc268_dell_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct hda_verb alc267_quanta_il1_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + { } +}; + +static void alc267_quanta_il1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc268_base_init_verbs[] = { + /* Unmute DAC0-1 and set vol = 0 */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + /* set PCBEEP vol = 0, mute connections */ + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + /* Unmute Selector 23h,24h and set the default input to mic-in */ + + {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + { } +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc268_volume_init_verbs[] = { + /* set output DAC */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + /* set PCBEEP vol = 0, mute connections */ + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), + _DEFINE_CAPSRC(1), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc268_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT), + _DEFINE_CAPSRC(2), + { } /* end */ +}; + +static const struct hda_input_mux alc268_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x3 }, + }, +}; + +static const struct hda_input_mux alc268_acer_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; + +static const struct hda_input_mux alc268_acer_dmic_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x6 }, + { "Line", 0x2 }, + }, +}; + +#ifdef CONFIG_SND_DEBUG +static const struct snd_kcontrol_new alc268_test_mixer[] = { + /* Volume widgets */ + HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT), + HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT), + HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT), + HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT), + HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT), + HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT), + /* The below appears problematic on some hardwares */ + /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/ + HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT), + + /* Modes for retasking pin widgets */ + ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT), + + /* Controls for GPIO pins, assuming they are configured as outputs */ + ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), + ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), + ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), + ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), + + /* Switches to allow the digital SPDIF output pin to be enabled. + * The ALC268 does not have an SPDIF input. + */ + ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01), + + /* A switch allowing EAPD to be enabled. Some laptops seem to use + * this output to turn on an external amplifier. + */ + ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), + ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), + + { } /* end */ +}; +#endif + +/* create input playback/capture controls for the given pin */ +static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, + const char *ctlname, int idx) +{ + hda_nid_t dac; + int err; + + switch (nid) { + case 0x14: + case 0x16: + dac = 0x02; + break; + case 0x15: + case 0x1a: /* ALC259/269 only */ + case 0x1b: /* ALC259/269 only */ + case 0x21: /* ALC269vb has this pin, too */ + dac = 0x03; + break; + default: + snd_printd(KERN_WARNING "hda_codec: " + "ignoring pin 0x%x as unknown\n", nid); + return 0; + } + if (spec->multiout.dac_nids[0] != dac && + spec->multiout.dac_nids[1] != dac) { + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, + HDA_COMPOSE_AMP_VAL(dac, 3, idx, + HDA_OUTPUT)); + if (err < 0) + return err; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; + } + + if (nid != 0x16) + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, + HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); + else /* mono */ + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, + HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT)); + if (err < 0) + return err; + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int err; + + spec->multiout.dac_nids = spec->private_dac_nids; + + nid = cfg->line_out_pins[0]; + if (nid) { + const char *name; + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + name = "Speaker"; + else + name = "Front"; + err = alc268_new_analog_output(spec, nid, name, 0); + if (err < 0) + return err; + } + + nid = cfg->speaker_pins[0]; + if (nid == 0x1d) { + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } else if (nid) { + err = alc268_new_analog_output(spec, nid, "Speaker", 0); + if (err < 0) + return err; + } + nid = cfg->hp_pins[0]; + if (nid) { + err = alc268_new_analog_output(spec, nid, "Headphone", 0); + if (err < 0) + return err; + } + + nid = cfg->line_out_pins[1] | cfg->line_out_pins[2]; + if (nid == 0x16) { + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono", + HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } + return 0; +} + +/* create playback/capture controls for input pins */ +static int alc268_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24); +} + +static void alc268_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type) +{ + int idx; + + alc_set_pin_output(codec, nid, pin_type); + if (nid == 0x14 || nid == 0x16) + idx = 0; + else + idx = 1; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); +} + +static void alc268_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc268_auto_set_output_and_unmute(codec, nid, pin_type); + } +} + +static void alc268_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + int i; + + for (i = 0; i < spec->autocfg.hp_outs; i++) { + pin = spec->autocfg.hp_pins[i]; + alc268_auto_set_output_and_unmute(codec, pin, PIN_HP); + } + for (i = 0; i < spec->autocfg.speaker_outs; i++) { + pin = spec->autocfg.speaker_pins[i]; + alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT); + } + if (spec->autocfg.mono_out_pin) + snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); +} + +static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0]; + hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; + hda_nid_t line_nid = spec->autocfg.line_out_pins[0]; + unsigned int dac_vol1, dac_vol2; + + if (line_nid == 0x1d || speaker_nid == 0x1d) { + snd_hda_codec_write(codec, speaker_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + /* mute mixer inputs from 0x1d */ + snd_hda_codec_write(codec, 0x0f, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); + snd_hda_codec_write(codec, 0x10, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); + } else { + /* unmute mixer inputs from 0x1d */ + snd_hda_codec_write(codec, 0x0f, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)); + snd_hda_codec_write(codec, 0x10, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)); + } + + dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */ + if (line_nid == 0x14) + dac_vol2 = AMP_OUT_ZERO; + else if (line_nid == 0x15) + dac_vol1 = AMP_OUT_ZERO; + if (hp_nid == 0x14) + dac_vol2 = AMP_OUT_ZERO; + else if (hp_nid == 0x15) + dac_vol1 = AMP_OUT_ZERO; + if (line_nid != 0x16 || hp_nid != 0x16 || + spec->autocfg.line_out_pins[1] != 0x16 || + spec->autocfg.line_out_pins[2] != 0x16) + dac_vol1 = dac_vol2 = AMP_OUT_ZERO; + + snd_hda_codec_write(codec, 0x02, 0, + AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1); + snd_hda_codec_write(codec, 0x03, 0, + AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2); +} + +/* pcm configuration: identical with ALC880 */ +#define alc268_pcm_analog_playback alc880_pcm_analog_playback +#define alc268_pcm_analog_capture alc880_pcm_analog_capture +#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture +#define alc268_pcm_digital_playback alc880_pcm_digital_playback + +/* + * BIOS auto configuration + */ +static int alc268_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc268_ignore[] = { 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc268_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) { + if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } + return 0; /* can't find valid BIOS pin config */ + } + err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc268_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = 2; + + dig_only: + /* digital only support output */ + alc_auto_parse_digital(codec); + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) + add_mixer(spec, alc268_beep_mixer); + + add_verb(spec, alc268_volume_init_verbs); + spec->num_mux_defs = 2; + spec->input_mux = &spec->private_imux[0]; + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + return 1; +} + +#define alc268_auto_init_analog_input alc882_auto_init_analog_input +#define alc268_auto_init_input_src alc882_auto_init_input_src + +/* init callback for auto-configuration model -- overriding the default init */ +static void alc268_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc268_auto_init_multi_out(codec); + alc268_auto_init_hp_out(codec); + alc268_auto_init_mono_speaker_out(codec); + alc268_auto_init_analog_input(codec); + alc268_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +/* + * configuration and preset + */ +static const char * const alc268_models[ALC268_MODEL_LAST] = { + [ALC267_QUANTA_IL1] = "quanta-il1", + [ALC268_3ST] = "3stack", + [ALC268_TOSHIBA] = "toshiba", + [ALC268_ACER] = "acer", + [ALC268_ACER_DMIC] = "acer-dmic", + [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", + [ALC268_DELL] = "dell", + [ALC268_ZEPTO] = "zepto", +#ifdef CONFIG_SND_DEBUG + [ALC268_TEST] = "test", +#endif + [ALC268_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc268_cfg_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", + ALC268_ACER_ASPIRE_ONE), + SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), + SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO), + SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0, + "Dell Inspiron Mini9/Vostro A90", ALC268_DELL), + /* almost compatible with toshiba but with optional digital outs; + * auto-probing seems working fine + */ + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series", + ALC268_AUTO), + SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), + SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), + SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), + {} +}; + +/* Toshiba laptops have no unique PCI SSID but only codec SSID */ +static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { + SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO), + SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO), + SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", + ALC268_TOSHIBA), + {} +}; + +static const struct alc_config_preset alc268_presets[] = { + [ALC267_QUANTA_IL1] = { + .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer, + alc268_capture_nosrc_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc267_quanta_il1_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc267_quanta_il1_setup, + .init_hook = alc_inithook, + }, + [ALC268_3ST] = { + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC268_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + }, + [ALC268_TOSHIBA] = { + .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_toshiba_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_toshiba_setup, + .init_hook = alc_inithook, + }, + [ALC268_ACER] = { + .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_acer_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_setup, + .init_hook = alc_inithook, + }, + [ALC268_ACER_DMIC] = { + .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_acer_dmic_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_setup, + .init_hook = alc_inithook, + }, + [ALC268_ACER_ASPIRE_ONE] = { + .mixers = { alc268_acer_aspire_one_mixer, + alc268_beep_mixer, + alc268_capture_nosrc_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_aspire_one_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_lc_setup, + .init_hook = alc_inithook, + }, + [ALC268_DELL] = { + .mixers = { alc268_dell_mixer, alc268_beep_mixer, + alc268_capture_nosrc_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_dell_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_dell_setup, + .init_hook = alc_inithook, + }, + [ALC268_ZEPTO] = { + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_toshiba_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC268_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_toshiba_setup, + .init_hook = alc_inithook, + }, +#ifdef CONFIG_SND_DEBUG + [ALC268_TEST] = { + .mixers = { alc268_test_mixer, alc268_capture_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_volume_init_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC268_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + }, +#endif +}; + +static int patch_alc268(struct hda_codec *codec) +{ + struct alc_spec *spec; + int board_config; + int i, has_beep, err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) return -ENOMEM; - knew->index = cidx; - if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_AMP_FLAG; - knew->private_value = val; + + codec->spec = spec; + + board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST, + alc268_models, + alc268_cfg_tbl); + + if (board_config < 0 || board_config >= ALC268_MODEL_LAST) + board_config = snd_hda_check_board_codec_sid_config(codec, + ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl); + + if (board_config < 0 || board_config >= ALC268_MODEL_LAST) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC268_AUTO; + } + + if (board_config == ALC268_AUTO) { + /* automatic parse from the BIOS config */ + err = alc268_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC268_3ST; + } + } + + if (board_config != ALC268_AUTO) + setup_preset(codec, &alc268_presets[board_config]); + + spec->stream_analog_playback = &alc268_pcm_analog_playback; + spec->stream_analog_capture = &alc268_pcm_analog_capture; + spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; + + spec->stream_digital_playback = &alc268_pcm_digital_playback; + + has_beep = 0; + for (i = 0; i < spec->num_mixers; i++) { + if (spec->mixers[i] == alc268_beep_mixer) { + has_beep = 1; + break; + } + } + + if (has_beep) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) + /* override the amp caps for beep generator */ + snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, + (0x0c << AC_AMPCAP_OFFSET_SHIFT) | + (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT)); + } + + if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { + /* check whether NID 0x07 is valid */ + unsigned int wcap = get_wcaps(codec, 0x07); + + spec->capsrc_nids = alc268_capsrc_nids; + /* get type */ + wcap = get_wcaps_type(wcap); + if (spec->auto_mic || + wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { + spec->adc_nids = alc268_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt); + if (spec->auto_mic) + fixup_automic_adc(codec); + if (spec->auto_mic || spec->input_mux->num_items == 1) + add_mixer(spec, alc268_capture_nosrc_mixer); + else + add_mixer(spec, alc268_capture_alt_mixer); + } else { + spec->adc_nids = alc268_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids); + add_mixer(spec, alc268_capture_mixer); + } + } + + spec->vmaster_nid = 0x02; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC268_AUTO) + spec->init_hook = alc268_auto_init; + spec->shutup = alc_eapd_shutup; + + alc_init_jacks(codec); + return 0; } -static int add_control_with_pfx(struct alc_spec *spec, int type, - const char *pfx, const char *dir, - const char *sfx, int cidx, unsigned long val) +/* + * ALC269 channel source setting (2 channel) + */ +#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID + +#define alc269_dac_nids alc260_dac_nids + +static const hda_nid_t alc269_adc_nids[1] = { + /* ADC1 */ + 0x08, +}; + +static const hda_nid_t alc269_capsrc_nids[1] = { + 0x23, +}; + +static const hda_nid_t alc269vb_adc_nids[1] = { + /* ADC1 */ + 0x09, +}; + +static const hda_nid_t alc269vb_capsrc_nids[1] = { + 0x22, +}; + +static const hda_nid_t alc269_adc_candidates[] = { + 0x08, 0x09, 0x07, 0x11, +}; + +#define alc269_modes alc260_modes +#define alc269_capture_source alc880_lg_lw_capture_source + +static const struct snd_kcontrol_new alc269_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_AMP_FLAG, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc269_lifebook_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_AMP_FLAG, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc269_laptop_mixer[] = { + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = { + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269_asus_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT), + { } /* end */ +}; + +/* capture mixer elements */ +static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +/* FSC amilo */ +#define alc269_fujitsu_mixer alc269_laptop_mixer + +static const struct hda_verb alc269_quanta_fl1_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + { } +}; + +static const struct hda_verb alc269_lifebook_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) { - char name[32]; - snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); - return add_control(spec, type, name, cidx, val); + alc_hp_automute(codec); + + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 0x0c); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x680); + + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 0x0c); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x480); } -#define add_pb_vol_ctrl(spec, type, pfx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) -#define add_pb_sw_ctrl(spec, type, pfx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) -#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) -#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) +#define alc269_lifebook_speaker_automute \ + alc269_quanta_fl1_speaker_automute -static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, - bool can_be_master, int *index) +static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) { - struct auto_pin_cfg *cfg = &spec->autocfg; - static const char * const chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; - - *index = 0; - if (cfg->line_outs == 1 && !spec->multi_ios && - !cfg->hp_outs && !cfg->speaker_outs && can_be_master) - return "Master"; + unsigned int present_laptop; + unsigned int present_dock; + + present_laptop = snd_hda_jack_detect(codec, 0x18); + present_dock = snd_hda_jack_detect(codec, 0x1b); + + /* Laptop mic port overrides dock mic port, design decision */ + if (present_dock) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x3); + if (present_laptop) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x0); + if (!present_dock && !present_laptop) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x1); +} - switch (cfg->line_out_type) { - case AUTO_PIN_SPEAKER_OUT: - if (cfg->line_outs == 1) - return "Speaker"; +static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_HP_EVENT: + alc269_quanta_fl1_speaker_automute(codec); break; - case AUTO_PIN_HP_OUT: - /* for multi-io case, only the primary out */ - if (ch && spec->multi_ios) - break; - *index = ch; - return "Headphone"; - default: - if (cfg->line_outs == 1 && !spec->multi_ios) - return "PCM"; + case ALC880_MIC_EVENT: + alc_mic_automute(codec); break; } - return chname[ch]; } -/* create input playback/capture controls for the given pin */ -static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, - const char *ctlname, int ctlidx, - int idx, hda_nid_t mix_nid) +static void alc269_lifebook_unsol_event(struct hda_codec *codec, + unsigned int res) { - int err; + if ((res >> 26) == ALC880_HP_EVENT) + alc269_lifebook_speaker_automute(codec); + if ((res >> 26) == ALC880_MIC_EVENT) + alc269_lifebook_mic_autoswitch(codec); +} - err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; +static void alc269_quanta_fl1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} + +static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) +{ + alc269_quanta_fl1_speaker_automute(codec); + alc_mic_automute(codec); +} + +static void alc269_lifebook_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.hp_pins[1] = 0x1a; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; +} + +static void alc269_lifebook_init_hook(struct hda_codec *codec) +{ + alc269_lifebook_speaker_automute(codec); + alc269_lifebook_mic_autoswitch(codec); +} + +static const struct hda_verb alc269_laptop_dmic_init_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static const struct hda_verb alc269_laptop_amic_init_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x06}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = { + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static const struct hda_verb alc271_acer_dmic_verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x22, AC_VERB_SET_CONNECT_SEL, 6}, + { } +}; + +static void alc269_laptop_amic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} + +static void alc269_laptop_dmic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 5; + spec->auto_mic = 1; +} + +static void alc269vb_laptop_amic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} + +static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 6; + spec->auto_mic = 1; +} + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc269_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* + * Set up output mixers (0x02 - 0x03) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* FIXME: use Mux-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* set EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc269vb_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* + * Set up output mixers (0x02 - 0x03) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* FIXME: use Mux-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x22, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* set EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +#define alc269_auto_create_multi_out_ctls \ + alc268_auto_create_multi_out_ctls +#define alc269_auto_create_input_ctls \ + alc268_auto_create_input_ctls + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc269_loopbacks alc880_loopbacks +#endif + +/* pcm configuration: identical with ALC880 */ +#define alc269_pcm_analog_playback alc880_pcm_analog_playback +#define alc269_pcm_analog_capture alc880_pcm_analog_capture +#define alc269_pcm_digital_playback alc880_pcm_digital_playback +#define alc269_pcm_digital_capture alc880_pcm_digital_capture + +static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ + /* NID is set in alc_build_pcms */ + .ops = { + .open = alc880_playback_pcm_open, + .prepare = alc880_playback_pcm_prepare, + .cleanup = alc880_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ + /* NID is set in alc_build_pcms */ +}; + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc269_mic2_for_mute_led(struct hda_codec *codec) +{ + switch (codec->subsystem_id) { + case 0x103c1586: + return 1; + } return 0; } -static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid) +static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) { - unsigned int pincap = snd_hda_query_pin_caps(codec, nid); - return (pincap & AC_PINCAP_IN) != 0; + /* update mute-LED according to the speaker mute state */ + if (nid == 0x01 || nid == 0x14) { + int pinval; + if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) & + HDA_AMP_MUTE) + pinval = 0x24; + else + pinval = 0x20; + /* mic2 vref pin is used for mute LED control */ + snd_hda_codec_update_cache(codec, 0x19, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinval); + } + return alc_check_power_status(codec, nid); } +#endif /* CONFIG_SND_HDA_POWER_SAVE */ -/* Parse the codec tree and retrieve ADCs and corresponding capsrc MUXs */ -static int alc_auto_fill_adc_caps(struct hda_codec *codec) +static int alc275_setup_dual_adc(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - hda_nid_t nid; - hda_nid_t *adc_nids = spec->private_adc_nids; - hda_nid_t *cap_nids = spec->private_capsrc_nids; - int max_nums = ARRAY_SIZE(spec->private_adc_nids); - bool indep_capsrc = false; - int i, nums = 0; - - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - hda_nid_t src; - const hda_nid_t *list; - unsigned int caps = get_wcaps(codec, nid); - int type = get_wcaps_type(caps); - - if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) - continue; - adc_nids[nums] = nid; - cap_nids[nums] = nid; - src = nid; - for (;;) { - int n; - type = get_wcaps_type(get_wcaps(codec, src)); - if (type == AC_WID_PIN) - break; - if (type == AC_WID_AUD_SEL) { - cap_nids[nums] = src; - indep_capsrc = true; - break; - } - n = snd_hda_get_conn_list(codec, src, &list); - if (n > 1) { - cap_nids[nums] = src; - indep_capsrc = true; - break; - } else if (n != 1) - break; - src = *list; + + if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic) + return 0; + if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) || + (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) { + if (spec->ext_mic.pin <= 0x12) { + spec->private_adc_nids[0] = 0x08; + spec->private_adc_nids[1] = 0x11; + spec->private_capsrc_nids[0] = 0x23; + spec->private_capsrc_nids[1] = 0x22; + } else { + spec->private_adc_nids[0] = 0x11; + spec->private_adc_nids[1] = 0x08; + spec->private_capsrc_nids[0] = 0x22; + spec->private_capsrc_nids[1] = 0x23; } - if (++nums >= max_nums) - break; + spec->adc_nids = spec->private_adc_nids; + spec->capsrc_nids = spec->private_capsrc_nids; + spec->num_adc_nids = 2; + spec->dual_adc_switch = 1; + snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n", + spec->adc_nids[0], spec->adc_nids[1]); + return 1; } - spec->adc_nids = spec->private_adc_nids; - spec->capsrc_nids = spec->private_capsrc_nids; - spec->num_adc_nids = nums; - return nums; + return 0; } -/* create playback/capture controls for input pins */ -static int alc_auto_create_input_ctls(struct hda_codec *codec) +/* different alc269-variants */ +enum { + ALC269_TYPE_NORMAL, + ALC269_TYPE_ALC258, + ALC269_TYPE_ALC259, + ALC269_TYPE_ALC269VB, + ALC269_TYPE_ALC270, + ALC269_TYPE_ALC271X, +}; + +/* + * BIOS auto configuration + */ +static int alc269_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t mixer = spec->mixer_nid; - struct hda_input_mux *imux = &spec->private_imux[0]; - int num_adcs; - int i, c, err, idx, type_idx = 0; - const char *prev_label = NULL; + int err; + static const hda_nid_t alc269_ignore[] = { 0x1d, 0 }; - num_adcs = alc_auto_fill_adc_caps(codec); - if (num_adcs < 0) - return 0; + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc269_ignore); + if (err < 0) + return err; - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin; - const char *label; + err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + if (spec->codec_variant == ALC269_TYPE_NORMAL) + err = alc269_auto_create_input_ctls(codec, &spec->autocfg); + else + err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0, + 0x22, 0); + if (err < 0) + return err; - pin = cfg->inputs[i].pin; - if (!alc_is_input_pin(codec, pin)) - continue; + spec->multiout.max_channels = spec->multiout.num_dacs * 2; - label = hda_get_autocfg_input_label(codec, cfg, i); - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; + alc_auto_parse_digital(codec); - if (mixer) { - idx = get_connection_index(codec, mixer, pin); - if (idx >= 0) { - err = new_analog_input(spec, pin, - label, type_idx, - idx, mixer); - if (err < 0) - return err; - } - } + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); - for (c = 0; c < num_adcs; c++) { - hda_nid_t cap = spec->capsrc_nids ? - spec->capsrc_nids[c] : spec->adc_nids[c]; - idx = get_connection_index(codec, cap, pin); - if (idx >= 0) { - spec->imux_pins[imux->num_items] = pin; - snd_hda_add_imux_item(imux, label, idx, NULL); - break; - } - } + if (spec->codec_variant != ALC269_TYPE_NORMAL) { + add_verb(spec, alc269vb_init_verbs); + alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21); + } else { + add_verb(spec, alc269_init_verbs); + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); } spec->num_mux_defs = 1; - spec->input_mux = imux; + spec->input_mux = &spec->private_imux[0]; - return 0; + if (!alc275_setup_dual_adc(codec)) + fillup_priv_adc_nids(codec, alc269_adc_candidates, + sizeof(alc269_adc_candidates)); + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + if (!spec->cap_mixer && !spec->no_analog) + set_capture_mixer(codec); + + return 1; } -static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid, - unsigned int pin_type) +#define alc269_auto_init_multi_out alc268_auto_init_multi_out +#define alc269_auto_init_hp_out alc268_auto_init_hp_out +#define alc269_auto_init_analog_input alc882_auto_init_analog_input +#define alc269_auto_init_input_src alc882_auto_init_input_src + + +/* init callback for auto-configuration model -- overriding the default init */ +static void alc269_auto_init(struct hda_codec *codec) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_type); - /* unmute pin */ - if (nid_has_mute(codec, nid, HDA_OUTPUT)) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); + struct alc_spec *spec = codec->spec; + alc269_auto_init_multi_out(codec); + alc269_auto_init_hp_out(codec); + alc269_auto_init_analog_input(codec); + if (!spec->dual_adc_switch) + alc269_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); } -static int get_pin_type(int line_out_type) +static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) { - if (line_out_type == AUTO_PIN_HP_OUT) - return PIN_HP; + int val = alc_read_coef_idx(codec, 0x04); + if (power_up) + val |= 1 << 11; else - return PIN_OUT; + val &= ~(1 << 11); + alc_write_coef_idx(codec, 0x04, val); } -static void alc_auto_init_analog_input(struct hda_codec *codec) +static void alc269_shutup(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) + alc269_toggle_power_output(codec, 0); + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + alc269_toggle_power_output(codec, 0); + msleep(150); + } +} - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - if (alc_is_input_pin(codec, nid)) { - alc_set_input_pin(codec, nid, cfg->inputs[i].type); - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } +#ifdef SND_HDA_NEEDS_RESUME +static int alc269_resume(struct hda_codec *codec) +{ + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + alc269_toggle_power_output(codec, 0); + msleep(150); } - /* mute all loopback inputs */ - if (spec->mixer_nid) { - int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL); - for (i = 0; i < nums; i++) - snd_hda_codec_write(codec, spec->mixer_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(i)); + codec->patch_ops.init(codec); + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { + alc269_toggle_power_output(codec, 1); + msleep(200); } + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) + alc269_toggle_power_output(codec, 1); + + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + hda_call_check_power_status(codec, 0x01); + return 0; } +#endif /* SND_HDA_NEEDS_RESUME */ -/* convert from MIX nid to DAC */ -static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid) +static void alc269_fixup_hweq(struct hda_codec *codec, + const struct alc_fixup *fix, int action) { - hda_nid_t list[5]; - int i, num; + int coef; - if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT) - return nid; - num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list)); - for (i = 0; i < num; i++) { - if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT) - return list[i]; - } - return 0; + if (action != ALC_FIXUP_ACT_INIT) + return; + coef = alc_read_coef_idx(codec, 0x1e); + alc_write_coef_idx(codec, 0x1e, coef | 0x80); +} + +static void alc271_fixup_dmic(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + static const struct hda_verb verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, + {} + }; + unsigned int cfg; + + if (strcmp(codec->chip_name, "ALC271X")) + return; + cfg = snd_hda_codec_get_pincfg(codec, 0x12); + if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED) + snd_hda_sequence_write(codec, verbs); } -/* go down to the selector widget before the mixer */ -static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin) +enum { + ALC269_FIXUP_SONY_VAIO, + ALC275_FIXUP_SONY_VAIO_GPIO2, + ALC269_FIXUP_DELL_M101Z, + ALC269_FIXUP_SKU_IGNORE, + ALC269_FIXUP_ASUS_G73JW, + ALC269_FIXUP_LENOVO_EAPD, + ALC275_FIXUP_SONY_HWEQ, + ALC271_FIXUP_DMIC, +}; + +static const struct alc_fixup alc269_fixups[] = { + [ALC269_FIXUP_SONY_VAIO] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, + {} + } + }, + [ALC275_FIXUP_SONY_VAIO_GPIO2] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x01, AC_VERB_SET_GPIO_MASK, 0x04}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_SONY_VAIO + }, + [ALC269_FIXUP_DELL_M101Z] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* Enables internal speaker */ + {0x20, AC_VERB_SET_COEF_INDEX, 13}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4040}, + {} + } + }, + [ALC269_FIXUP_SKU_IGNORE] = { + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, + }, + [ALC269_FIXUP_ASUS_G73JW] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x17, 0x99130111 }, /* subwoofer */ + { } + } + }, + [ALC269_FIXUP_LENOVO_EAPD] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, + {} + } + }, + [ALC275_FIXUP_SONY_HWEQ] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc269_fixup_hweq, + .chained = true, + .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 + }, + [ALC271_FIXUP_DMIC] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc271_fixup_dmic, + }, +}; + +static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), + SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), + SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), + SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), + SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), + SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), + {} +}; + + +/* + * configuration and preset + */ +static const char * const alc269_models[ALC269_MODEL_LAST] = { + [ALC269_BASIC] = "basic", + [ALC269_QUANTA_FL1] = "quanta", + [ALC269_AMIC] = "laptop-amic", + [ALC269_DMIC] = "laptop-dmic", + [ALC269_FUJITSU] = "fujitsu", + [ALC269_LIFEBOOK] = "lifebook", + [ALC269_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc269_cfg_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), + SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER), + SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", + ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", + ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", + ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC), + SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO), + SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), + SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC), + SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), + SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC), + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC), + SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC), + SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC), + {} +}; + +static const struct alc_config_preset alc269_presets[] = { + [ALC269_BASIC] = { + .mixers = { alc269_base_mixer }, + .init_verbs = { alc269_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + }, + [ALC269_QUANTA_FL1] = { + .mixers = { alc269_quanta_fl1_mixer }, + .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .unsol_event = alc269_quanta_fl1_unsol_event, + .setup = alc269_quanta_fl1_setup, + .init_hook = alc269_quanta_fl1_init_hook, + }, + [ALC269_AMIC] = { + .mixers = { alc269_laptop_mixer }, + .cap_mixer = alc269_laptop_analog_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_laptop_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269_laptop_amic_setup, + .init_hook = alc_inithook, + }, + [ALC269_DMIC] = { + .mixers = { alc269_laptop_mixer }, + .cap_mixer = alc269_laptop_digital_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_laptop_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269_laptop_dmic_setup, + .init_hook = alc_inithook, + }, + [ALC269VB_AMIC] = { + .mixers = { alc269vb_laptop_mixer }, + .cap_mixer = alc269vb_laptop_analog_capture_mixer, + .init_verbs = { alc269vb_init_verbs, + alc269vb_laptop_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269vb_laptop_amic_setup, + .init_hook = alc_inithook, + }, + [ALC269VB_DMIC] = { + .mixers = { alc269vb_laptop_mixer }, + .cap_mixer = alc269vb_laptop_digital_capture_mixer, + .init_verbs = { alc269vb_init_verbs, + alc269vb_laptop_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269vb_laptop_dmic_setup, + .init_hook = alc_inithook, + }, + [ALC269_FUJITSU] = { + .mixers = { alc269_fujitsu_mixer }, + .cap_mixer = alc269_laptop_digital_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_laptop_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269_laptop_dmic_setup, + .init_hook = alc_inithook, + }, + [ALC269_LIFEBOOK] = { + .mixers = { alc269_lifebook_mixer }, + .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .unsol_event = alc269_lifebook_unsol_event, + .setup = alc269_lifebook_setup, + .init_hook = alc269_lifebook_init_hook, + }, + [ALC271_ACER] = { + .mixers = { alc269_asus_mixer }, + .cap_mixer = alc269vb_laptop_digital_capture_mixer, + .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .adc_nids = alc262_dmic_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids), + .capsrc_nids = alc262_dmic_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .dig_out_nid = ALC880_DIGOUT_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc269vb_laptop_dmic_setup, + .init_hook = alc_inithook, + }, +}; + +static int alc269_fill_coef(struct hda_codec *codec) { - hda_nid_t srcs[5]; - int num = snd_hda_get_connections(codec, pin, srcs, - ARRAY_SIZE(srcs)); - if (num != 1 || - get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL) - return pin; - return srcs[0]; -} + int val; -/* get MIX nid connected to the given pin targeted to DAC */ -static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - hda_nid_t mix[5]; - int i, num; + if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) { + alc_write_coef_idx(codec, 0xf, 0x960b); + alc_write_coef_idx(codec, 0xe, 0x8817); + } - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, mix[i]) == dac) - return mix[i]; + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) { + alc_write_coef_idx(codec, 0xf, 0x960b); + alc_write_coef_idx(codec, 0xe, 0x8814); } - return 0; -} -/* select the connection from pin to DAC if needed */ -static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - hda_nid_t mix[5]; - int i, num; + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { + val = alc_read_coef_idx(codec, 0x04); + /* Power up output pin */ + alc_write_coef_idx(codec, 0x04, val | (1<<11)); + } - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); - if (num < 2) - return 0; - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, mix[i]) == dac) { - snd_hda_codec_update_cache(codec, pin, 0, - AC_VERB_SET_CONNECT_SEL, i); - return 0; + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + val = alc_read_coef_idx(codec, 0xd); + if ((val & 0x0c00) >> 10 != 0x1) { + /* Capless ramp up clock control */ + alc_write_coef_idx(codec, 0xd, val | (1<<10)); + } + val = alc_read_coef_idx(codec, 0x17); + if ((val & 0x01c0) >> 6 != 0x4) { + /* Class D power on reset */ + alc_write_coef_idx(codec, 0x17, val | (1<<7)); } } - return 0; -} -/* look for an empty DAC slot */ -static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t srcs[5]; - int i, num; + val = alc_read_coef_idx(codec, 0xd); /* Class D */ + alc_write_coef_idx(codec, 0xd, val | (1<<14)); - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); - for (i = 0; i < num; i++) { - hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); - if (!nid) - continue; - if (found_in_nid_list(nid, spec->multiout.dac_nids, - spec->multiout.num_dacs)) - continue; - if (spec->multiout.hp_nid == nid) - continue; - if (found_in_nid_list(nid, spec->multiout.extra_out_nid, - ARRAY_SIZE(spec->multiout.extra_out_nid))) - continue; - return nid; - } - return 0; -} + val = alc_read_coef_idx(codec, 0x4); /* HP */ + alc_write_coef_idx(codec, 0x4, val | (1<<11)); -static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t sel = alc_go_down_to_selector(codec, pin); - if (snd_hda_get_conn_list(codec, sel, NULL) == 1) - return alc_auto_look_for_dac(codec, pin); return 0; } -/* fill in the dac_nids table from the parsed pin configuration */ -static int alc_auto_fill_dac_nids(struct hda_codec *codec) +static int patch_alc269(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - bool redone = false; - int i; + struct alc_spec *spec; + int board_config, coef; + int err; - again: - spec->multiout.num_dacs = 0; - spec->multiout.hp_nid = 0; - spec->multiout.extra_out_nid[0] = 0; - memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); - spec->multiout.dac_nids = spec->private_dac_nids; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; - /* fill hard-wired DACs first */ - if (!redone) { - for (i = 0; i < cfg->line_outs; i++) - spec->private_dac_nids[i] = - get_dac_if_single(codec, cfg->line_out_pins[i]); - if (cfg->hp_outs) - spec->multiout.hp_nid = - get_dac_if_single(codec, cfg->hp_pins[0]); - if (cfg->speaker_outs) - spec->multiout.extra_out_nid[0] = - get_dac_if_single(codec, cfg->speaker_pins[0]); - } + codec->spec = spec; - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t pin = cfg->line_out_pins[i]; - if (spec->private_dac_nids[i]) - continue; - spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin); - if (!spec->private_dac_nids[i] && !redone) { - /* if we can't find primary DACs, re-probe without - * checking the hard-wired DACs - */ - redone = true; - goto again; - } + alc_auto_parse_customize_define(codec); + + if (codec->vendor_id == 0x10ec0269) { + coef = alc_read_coef_idx(codec, 0); + if ((coef & 0x00f0) == 0x0010) { + if (codec->bus->pci->subsystem_vendor == 0x1025 && + spec->cdefine.platform_type == 1) { + alc_codec_rename(codec, "ALC271X"); + spec->codec_variant = ALC269_TYPE_ALC271X; + } else if ((coef & 0xf000) == 0x1000) { + spec->codec_variant = ALC269_TYPE_ALC270; + } else if ((coef & 0xf000) == 0x2000) { + alc_codec_rename(codec, "ALC259"); + spec->codec_variant = ALC269_TYPE_ALC259; + } else if ((coef & 0xf000) == 0x3000) { + alc_codec_rename(codec, "ALC258"); + spec->codec_variant = ALC269_TYPE_ALC258; + } else { + alc_codec_rename(codec, "ALC269VB"); + spec->codec_variant = ALC269_TYPE_ALC269VB; + } + } else + alc_fix_pll_init(codec, 0x20, 0x04, 15); + alc269_fill_coef(codec); } - for (i = 0; i < cfg->line_outs; i++) { - if (spec->private_dac_nids[i]) - spec->multiout.num_dacs++; - else - memmove(spec->private_dac_nids + i, - spec->private_dac_nids + i + 1, - sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); + board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, + alc269_models, + alc269_cfg_tbl); + + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC269_AUTO; } - if (cfg->hp_outs && !spec->multiout.hp_nid) - spec->multiout.hp_nid = - alc_auto_look_for_dac(codec, cfg->hp_pins[0]); - if (cfg->speaker_outs && !spec->multiout.extra_out_nid[0]) - spec->multiout.extra_out_nid[0] = - alc_auto_look_for_dac(codec, cfg->speaker_pins[0]); + if (board_config == ALC269_AUTO) { + alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } - return 0; -} + if (board_config == ALC269_AUTO) { + /* automatic parse from the BIOS config */ + err = alc269_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC269_BASIC; + } + } -static int alc_auto_add_vol_ctl(struct hda_codec *codec, - const char *pfx, int cidx, - hda_nid_t nid, unsigned int chs) -{ - if (!nid) - return 0; - return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); -} + if (has_cdefine_beep(codec)) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + } -#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \ - alc_auto_add_vol_ctl(codec, pfx, cidx, nid, 3) + if (board_config != ALC269_AUTO) + setup_preset(codec, &alc269_presets[board_config]); -/* create a mute-switch for the given mixer widget; - * if it has multiple sources (e.g. DAC and loopback), create a bind-mute - */ -static int alc_auto_add_sw_ctl(struct hda_codec *codec, - const char *pfx, int cidx, - hda_nid_t nid, unsigned int chs) -{ - int wid_type; - int type; - unsigned long val; - if (!nid) - return 0; - wid_type = get_wcaps_type(get_wcaps(codec, nid)); - if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) { - type = ALC_CTL_WIDGET_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT); - } else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) { - type = ALC_CTL_WIDGET_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT); + if (board_config == ALC269_QUANTA_FL1) { + /* Due to a hardware problem on Lenovo Ideadpad, we need to + * fix the sample rate of analog I/O to 44.1kHz + */ + spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; + spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; + } else if (spec->dual_adc_switch) { + spec->stream_analog_playback = &alc269_pcm_analog_playback; + /* switch ADC dynamically */ + spec->stream_analog_capture = &dualmic_pcm_analog_capture; } else { - type = ALC_CTL_BIND_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT); + spec->stream_analog_playback = &alc269_pcm_analog_playback; + spec->stream_analog_capture = &alc269_pcm_analog_capture; + } + spec->stream_digital_playback = &alc269_pcm_digital_playback; + spec->stream_digital_capture = &alc269_pcm_digital_capture; + + if (!spec->adc_nids) { /* wasn't filled automatically? use default */ + if (spec->codec_variant == ALC269_TYPE_NORMAL) { + spec->adc_nids = alc269_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); + spec->capsrc_nids = alc269_capsrc_nids; + } else { + spec->adc_nids = alc269vb_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids); + spec->capsrc_nids = alc269vb_capsrc_nids; + } } - return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); -} -#define alc_auto_add_stereo_sw(codec, pfx, cidx, nid) \ - alc_auto_add_sw_ctl(codec, pfx, cidx, nid, 3) + if (!spec->cap_mixer) + set_capture_mixer(codec); + if (has_cdefine_beep(codec)) + set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); -static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac) -{ - hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac); - if (nid_has_mute(codec, pin, HDA_OUTPUT)) - return pin; - else if (mix && nid_has_mute(codec, mix, HDA_INPUT)) - return mix; - else if (nid_has_mute(codec, dac, HDA_OUTPUT)) - return dac; - return 0; -} + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + + spec->vmaster_nid = 0x02; + + codec->patch_ops = alc_patch_ops; +#ifdef SND_HDA_NEEDS_RESUME + codec->patch_ops.resume = alc269_resume; +#endif + if (board_config == ALC269_AUTO) + spec->init_hook = alc269_auto_init; + spec->shutup = alc269_shutup; + + alc_init_jacks(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc269_loopbacks; + if (alc269_mic2_for_mute_led(codec)) + codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps; +#endif -static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac) -{ - hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac); - if (nid_has_volume(codec, dac, HDA_OUTPUT)) - return dac; - else if (nid_has_volume(codec, mix, HDA_OUTPUT)) - return mix; - else if (nid_has_volume(codec, pin, HDA_OUTPUT)) - return pin; return 0; } -/* add playback controls from the parsed DAC table */ -static int alc_auto_create_multi_out_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct alc_spec *spec = codec->spec; - int i, err, noutputs; +/* + * ALC861 channel source setting (2/6 channel selection for 3-stack) + */ - noutputs = cfg->line_outs; - if (spec->multi_ios > 0) - noutputs += spec->multi_ios; +/* + * set the path ways for 2 channel output + * need to set the codec line out and mic 1 pin widgets to inputs + */ +static const struct hda_verb alc861_threestack_ch2_init[] = { + /* set pin widget 1Ah (line in) for input */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* set pin widget 18h (mic1/2) for input, for mic also enable + * the vref + */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - for (i = 0; i < noutputs; i++) { - const char *name; - int index; - hda_nid_t dac, pin; - hda_nid_t sw, vol; + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ +#endif + { } /* end */ +}; +/* + * 6ch mode + * need to set the codec line out and mic 1 pin widgets to outputs + */ +static const struct hda_verb alc861_threestack_ch6_init[] = { + /* set pin widget 1Ah (line in) for output (Back Surround)*/ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* set pin widget 18h (mic1) for output (CLFE)*/ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - dac = spec->multiout.dac_nids[i]; - if (!dac) - continue; - if (i >= cfg->line_outs) - pin = spec->multi_io[i - 1].pin; - else - pin = cfg->line_out_pins[i]; + { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, - sw = alc_look_for_out_mute_nid(codec, pin, dac); - vol = alc_look_for_out_vol_nid(codec, pin, dac); - name = alc_get_line_out_pfx(spec, i, true, &index); - if (!name) { - /* Center/LFE */ - err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1); - if (err < 0) - return err; - err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2); - if (err < 0) - return err; - err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1); - if (err < 0) - return err; - err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2); - if (err < 0) - return err; - } else { - err = alc_auto_add_stereo_vol(codec, name, index, vol); - if (err < 0) - return err; - err = alc_auto_add_stereo_sw(codec, name, index, sw); - if (err < 0) - return err; - } - } - return 0; -} + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ +#endif + { } /* end */ +}; + +static const struct hda_channel_mode alc861_threestack_modes[2] = { + { 2, alc861_threestack_ch2_init }, + { 6, alc861_threestack_ch6_init }, +}; +/* Set mic1 as input and unmute the mixer */ +static const struct hda_verb alc861_uniwill_m31_ch2_init[] = { + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ + { } /* end */ +}; +/* Set mic1 as output and mute mixer */ +static const struct hda_verb alc861_uniwill_m31_ch4_init[] = { + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ + { } /* end */ +}; + +static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = { + { 2, alc861_uniwill_m31_ch2_init }, + { 4, alc861_uniwill_m31_ch4_init }, +}; + +/* Set mic1 and line-in as input and unmute the mixer */ +static const struct hda_verb alc861_asus_ch2_init[] = { + /* set pin widget 1Ah (line in) for input */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* set pin widget 18h (mic1/2) for input, for mic also enable + * the vref + */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ +#endif + { } /* end */ +}; +/* Set mic1 nad line-in as output and mute mixer */ +static const struct hda_verb alc861_asus_ch6_init[] = { + /* set pin widget 1Ah (line in) for output (Back Surround)*/ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ + /* set pin widget 18h (mic1) for output (CLFE)*/ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ + { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, + + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ +#endif + { } /* end */ +}; -/* add playback controls for speaker and HP outputs */ -static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac, const char *pfx) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t sw, vol; - int err; +static const struct hda_channel_mode alc861_asus_modes[2] = { + { 2, alc861_asus_ch2_init }, + { 6, alc861_asus_ch6_init }, +}; - if (!pin) - return 0; - if (!dac) { - /* the corresponding DAC is already occupied */ - if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) - return 0; /* no way */ - /* create a switch only */ - return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); - } +/* patch-ALC861 */ + +static const struct snd_kcontrol_new alc861_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), + + /*Input mixer control */ + /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - sw = alc_look_for_out_mute_nid(codec, pin, dac); - vol = alc_look_for_out_vol_nid(codec, pin, dac); - err = alc_auto_add_stereo_vol(codec, pfx, 0, vol); - if (err < 0) - return err; - err = alc_auto_add_stereo_sw(codec, pfx, 0, sw); - if (err < 0) - return err; - return 0; -} + { } /* end */ +}; -static int alc_auto_create_hp_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], - spec->multiout.hp_nid, - "Headphone"); -} +static const struct snd_kcontrol_new alc861_3ST_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ + + /* Input mixer control */ + /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), -static int alc_auto_create_speaker_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], - spec->multiout.extra_out_nid[0], - "Speaker"); -} + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + .private_value = ARRAY_SIZE(alc861_threestack_modes), + }, + { } /* end */ +}; -static void alc_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t pin, int pin_type, - hda_nid_t dac) -{ - int i, num; - hda_nid_t nid, mix = 0; - hda_nid_t srcs[HDA_MAX_CONNECTIONS]; +static const struct snd_kcontrol_new alc861_toshiba_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - alc_set_pin_output(codec, pin, pin_type); - nid = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, srcs[i]) != dac) - continue; - mix = srcs[i]; - break; - } - if (!mix) - return; + { } /* end */ +}; - /* need the manual connection? */ - if (num > 1) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i); - /* unmute mixer widget inputs */ - if (nid_has_mute(codec, mix, HDA_INPUT)) { - snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(1)); - } - /* initialize volume */ - nid = alc_look_for_out_vol_nid(codec, pin, dac); - if (nid) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_ZERO); -} +static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ + + /* Input mixer control */ + /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), -static void alc_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int pin_type = get_pin_type(spec->autocfg.line_out_type); - int i; + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes), + }, + { } /* end */ +}; - for (i = 0; i <= HDA_SIDE; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - if (nid) - alc_auto_set_output_and_unmute(codec, nid, pin_type, - spec->multiout.dac_nids[i]); - } -} +static const struct snd_kcontrol_new alc861_asus_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), + + /* Input mixer control */ + HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), -static void alc_auto_init_extra_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t pin; + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + .private_value = ARRAY_SIZE(alc861_asus_modes), + }, + { } +}; - pin = spec->autocfg.hp_pins[0]; - if (pin) - alc_auto_set_output_and_unmute(codec, pin, PIN_HP, - spec->multiout.hp_nid); - pin = spec->autocfg.speaker_pins[0]; - if (pin) - alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, - spec->multiout.extra_out_nid[0]); -} +/* additional mixer */ +static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + { } +}; /* - * multi-io helper + * generic initialization of ADC, input mixers and output mixers */ -static int alc_auto_fill_multi_ios(struct hda_codec *codec, - unsigned int location) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int type, i, num_pins = 0; +static const struct hda_verb alc861_base_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - hda_nid_t dac; - unsigned int defcfg, caps; - if (cfg->inputs[i].type != type) - continue; - defcfg = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) - continue; - if (location && get_defcfg_location(defcfg) != location) - continue; - caps = snd_hda_query_pin_caps(codec, nid); - if (!(caps & AC_PINCAP_OUT)) - continue; - dac = alc_auto_look_for_dac(codec, nid); - if (!dac) - continue; - spec->multi_io[num_pins].pin = nid; - spec->multi_io[num_pins].dac = dac; - num_pins++; - spec->private_dac_nids[spec->multiout.num_dacs++] = dac; - } - } - spec->multiout.num_dacs = 1; - if (num_pins < 2) - return 0; - return num_pins; -} + { } +}; -static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; +static const struct hda_verb alc861_threestack_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + { } +}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->multi_ios + 1; - if (uinfo->value.enumerated.item > spec->multi_ios) - uinfo->value.enumerated.item = spec->multi_ios; - sprintf(uinfo->value.enumerated.name, "%dch", - (uinfo->value.enumerated.item + 1) * 2); - return 0; -} +static const struct hda_verb alc861_uniwill_m31_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + /* this has to be set to VREF80 */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + { } +}; -static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2; - return 0; -} +static const struct hda_verb alc861_asus_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) + * according to codec#0 this is the HP jack + */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */ + /* route front PCM to HP */ + { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + /* this has to be set to VREF80 */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + { } +}; -static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid = spec->multi_io[idx].pin; +/* additional init verbs for ASUS laptops */ +static const struct hda_verb alc861_asus_laptop_init_verbs[] = { + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */ + { } +}; - if (!spec->multi_io[idx].ctl_in) - spec->multi_io[idx].ctl_in = - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (output) { - snd_hda_codec_update_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_OUT); - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, 0); - alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac); - } else { - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_update_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - spec->multi_io[idx].ctl_in); - } - return 0; -} +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc861_auto_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */ -static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int i, ch; + { } +}; - ch = ucontrol->value.enumerated.item[0]; - if (ch < 0 || ch > spec->multi_ios) - return -EINVAL; - if (ch == (spec->ext_channel_count - 1) / 2) - return 0; - spec->ext_channel_count = (ch + 1) * 2; - for (i = 0; i < spec->multi_ios; i++) - alc_set_multi_io(codec, i, i < ch); - spec->multiout.max_channels = spec->ext_channel_count; - if (spec->need_dac_fix && !spec->const_channel_count) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - return 1; -} +static const struct hda_verb alc861_toshiba_init_verbs[] = { + {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, -static const struct snd_kcontrol_new alc_auto_channel_mode_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_auto_ch_mode_info, - .get = alc_auto_ch_mode_get, - .put = alc_auto_ch_mode_put, + { } }; -static int alc_auto_add_multi_channel_mode(struct hda_codec *codec, - int (*fill_dac)(struct hda_codec *)) +/* toggle speaker-output according to the hp-jack state */ +static void alc861_toshiba_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int location, defcfg; - int num_pins; + unsigned int present = snd_hda_jack_detect(codec, 0x0f); - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->hp_outs == 1) { - /* use HP as primary out */ - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - cfg->line_out_type = AUTO_PIN_HP_OUT; - if (fill_dac) - fill_dac(codec); - } - if (cfg->line_outs != 1 || - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - return 0; + snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); +} - defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); - location = get_defcfg_location(defcfg); +static void alc861_toshiba_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc861_toshiba_automute(codec); +} - num_pins = alc_auto_fill_multi_ios(codec, location); - if (num_pins > 0) { - struct snd_kcontrol_new *knew; +/* pcm configuration: identical with ALC880 */ +#define alc861_pcm_analog_playback alc880_pcm_analog_playback +#define alc861_pcm_analog_capture alc880_pcm_analog_capture +#define alc861_pcm_digital_playback alc880_pcm_digital_playback +#define alc861_pcm_digital_capture alc880_pcm_digital_capture - knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_auto_channel_mode_enum; - knew->name = kstrdup("Channel Mode", GFP_KERNEL); - if (!knew->name) - return -ENOMEM; - spec->multi_ios = num_pins; - spec->ext_channel_count = 2; - spec->multiout.num_dacs = num_pins + 1; - } - return 0; -} +#define ALC861_DIGOUT_NID 0x07 + +static const struct hda_channel_mode alc861_8ch_modes[1] = { + { 8, NULL } +}; + +static const hda_nid_t alc861_dac_nids[4] = { + /* front, surround, clfe, side */ + 0x03, 0x06, 0x05, 0x04 +}; + +static const hda_nid_t alc660_dac_nids[3] = { + /* front, clfe, surround */ + 0x03, 0x05, 0x06 +}; -/* filter out invalid adc_nids (and capsrc_nids) that don't give all - * active input pins - */ -static void alc_remove_invalid_adc_nids(struct hda_codec *codec) +static const hda_nid_t alc861_adc_nids[1] = { + /* ADC0-2 */ + 0x08, +}; + +static const struct hda_input_mux alc861_capture_source = { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x3 }, + { "Line", 0x1 }, + { "CD", 0x4 }, + { "Mixer", 0x5 }, + }, +}; + +static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin) { struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; - hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)]; - hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)]; - int i, n, nums; - - imux = spec->input_mux; - if (!imux) - return; - if (spec->dyn_adc_switch) - return; + hda_nid_t mix, srcs[5]; + int i, j, num; - nums = 0; - for (n = 0; n < spec->num_adc_nids; n++) { - hda_nid_t cap = spec->private_capsrc_nids[n]; - int num_conns = snd_hda_get_conn_list(codec, cap, NULL); - for (i = 0; i < imux->num_items; i++) { - hda_nid_t pin = spec->imux_pins[i]; - if (pin) { - if (get_connection_index(codec, cap, pin) < 0) - break; - } else if (num_conns <= imux->items[i].index) + if (snd_hda_get_connections(codec, pin, &mix, 1) != 1) + return 0; + num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs)); + if (num < 0) + return 0; + for (i = 0; i < num; i++) { + unsigned int type; + type = get_wcaps_type(get_wcaps(codec, srcs[i])); + if (type != AC_WID_AUD_OUT) + continue; + for (j = 0; j < spec->multiout.num_dacs; j++) + if (spec->multiout.dac_nids[j] == srcs[i]) break; - } - if (i >= imux->num_items) { - adc_nids[nums] = spec->private_adc_nids[n]; - capsrc_nids[nums++] = cap; - } - } - if (!nums) { - /* check whether ADC-switch is possible */ - if (!alc_check_dyn_adc_switch(codec)) { - printk(KERN_WARNING "hda_codec: %s: no valid ADC found;" - " using fallback 0x%x\n", - codec->chip_name, spec->private_adc_nids[0]); - spec->num_adc_nids = 1; - spec->auto_mic = 0; - return; - } - } else if (nums != spec->num_adc_nids) { - memcpy(spec->private_adc_nids, adc_nids, - nums * sizeof(hda_nid_t)); - memcpy(spec->private_capsrc_nids, capsrc_nids, - nums * sizeof(hda_nid_t)); - spec->num_adc_nids = nums; + if (j >= spec->multiout.num_dacs) + return srcs[i]; } - - if (spec->auto_mic) - alc_auto_mic_check_imux(codec); /* check auto-mic setups */ - else if (spec->input_mux->num_items == 1) - spec->num_adc_nids = 1; /* reduce to a single ADC */ + return 0; } -/* - * initialize ADC paths - */ -static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx) +/* fill in the dac_nids table from the parsed pin configuration */ +static int alc861_auto_fill_dac_nids(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { struct alc_spec *spec = codec->spec; - hda_nid_t nid; + int i; + hda_nid_t nid, dac; - nid = spec->adc_nids[adc_idx]; - /* mute ADC */ - if (nid_has_mute(codec, nid, HDA_INPUT)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - return; + spec->multiout.dac_nids = spec->private_dac_nids; + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + dac = alc861_look_for_dac(codec, nid); + if (!dac) + continue; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } - if (!spec->capsrc_nids) - return; - nid = spec->capsrc_nids[adc_idx]; - if (nid_has_mute(codec, nid, HDA_OUTPUT)) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); + return 0; } -static void alc_auto_init_input_src(struct hda_codec *codec) +static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx, + hda_nid_t nid, int idx, unsigned int chs) { - struct alc_spec *spec = codec->spec; - int c, nums; - - for (c = 0; c < spec->num_adc_nids; c++) - alc_auto_init_adc(codec, c); - if (spec->dyn_adc_switch) - nums = 1; - else - nums = spec->num_adc_nids; - for (c = 0; c < nums; c++) - alc_mux_select(codec, 0, spec->cur_mux[c], true); + return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); } -/* add mic boosts if needed */ -static int alc_auto_add_mic_boost(struct hda_codec *codec) +#define alc861_create_out_sw(codec, pfx, nid, chs) \ + __alc861_create_out_sw(codec, pfx, nid, 0, chs) + +/* add playback controls from the parsed DAC table */ +static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - int type_idx = 0; + static const char * const chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; + const char *pfx = alc_get_line_out_pfx(spec, true); hda_nid_t nid; - const char *prev_label = NULL; - - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type > AUTO_PIN_MIC) - break; - nid = cfg->inputs[i].pin; - if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { - const char *label; - char boost_label[32]; + int i, err, noutputs; - label = hda_get_autocfg_input_label(codec, cfg, i); - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; - snprintf(boost_label, sizeof(boost_label), - "%s Boost Volume", label); - err = add_control(spec, ALC_CTL_WIDGET_VOL, - boost_label, type_idx, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + for (i = 0; i < noutputs; i++) { + nid = spec->multiout.dac_nids[i]; + if (!nid) + continue; + if (!pfx && i == 2) { + /* Center/LFE */ + err = alc861_create_out_sw(codec, "Center", nid, 1); + if (err < 0) + return err; + err = alc861_create_out_sw(codec, "LFE", nid, 2); + if (err < 0) + return err; + } else { + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __alc861_create_out_sw(codec, name, nid, index, 3); if (err < 0) return err; } @@ -3391,247 +16085,349 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) return 0; } -/* select or unmute the given capsrc route */ -static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, - int idx) -{ - if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { - snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, - HDA_AMP_MUTE, 0); - } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) { - snd_hda_codec_write_cache(codec, cap, 0, - AC_VERB_SET_CONNECT_SEL, idx); - } -} - -/* set the default connection to that pin */ -static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) +static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) { struct alc_spec *spec = codec->spec; - int i; + int err; + hda_nid_t nid; if (!pin) return 0; - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t cap = spec->capsrc_nids ? - spec->capsrc_nids[i] : spec->adc_nids[i]; - int idx; - idx = get_connection_index(codec, cap, pin); - if (idx < 0) - continue; - select_or_unmute_capsrc(codec, cap, idx); - return i; /* return the found index */ + if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) { + nid = alc861_look_for_dac(codec, pin); + if (nid) { + err = alc861_create_out_sw(codec, "Headphone", nid, 3); + if (err < 0) + return err; + spec->multiout.hp_nid = nid; + } } - return -1; /* not found */ + return 0; } -/* initialize some special cases for input sources */ -static void alc_init_special_input_src(struct hda_codec *codec) +/* create playback/capture controls for input pins */ +static int alc861_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.num_inputs; i++) - init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin); + return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0); } -/* assign appropriate capture mixers */ -static void set_capture_mixer(struct hda_codec *codec) +static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, + int pin_type, hda_nid_t dac) { - struct alc_spec *spec = codec->spec; - static const struct snd_kcontrol_new *caps[2][3] = { - { alc_capture_mixer_nosrc1, - alc_capture_mixer_nosrc2, - alc_capture_mixer_nosrc3 }, - { alc_capture_mixer1, - alc_capture_mixer2, - alc_capture_mixer3 }, - }; + hda_nid_t mix, srcs[5]; + int i, num; - /* check whether either of ADC or MUX has a volume control */ - if (!nid_has_volume(codec, spec->adc_nids[0], HDA_INPUT)) { - if (!spec->capsrc_nids) - return; /* no volume */ - if (!nid_has_volume(codec, spec->capsrc_nids[0], HDA_OUTPUT)) - return; /* no volume in capsrc, too */ - spec->vol_in_capsrc = 1; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_type); + snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + if (snd_hda_get_connections(codec, nid, &mix, 1) != 1) + return; + num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs)); + if (num < 0) + return; + for (i = 0; i < num; i++) { + unsigned int mute; + if (srcs[i] == dac || srcs[i] == 0x15) + mute = AMP_IN_UNMUTE(i); + else + mute = AMP_IN_MUTE(i); + snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, + mute); } +} - if (spec->num_adc_nids > 0) { - int mux = 0; - int num_adcs = 0; +static void alc861_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; - if (spec->input_mux && spec->input_mux->num_items > 1) - mux = 1; - if (spec->auto_mic) { - num_adcs = 1; - mux = 0; - } else if (spec->dyn_adc_switch) - num_adcs = 1; - if (!num_adcs) { - if (spec->num_adc_nids > 3) - spec->num_adc_nids = 3; - else if (!spec->num_adc_nids) - return; - num_adcs = spec->num_adc_nids; - } - spec->cap_mixer = caps[mux][num_adcs - 1]; + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + if (nid) + alc861_auto_set_output_and_unmute(codec, nid, pin_type, + spec->multiout.dac_nids[i]); } } -/* - * standard auto-parser initializations - */ -static void alc_auto_init_std(struct hda_codec *codec) +static void alc861_auto_init_hp_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - alc_auto_init_multi_out(codec); - alc_auto_init_extra_out(codec); - alc_auto_init_analog_input(codec); - alc_auto_init_input_src(codec); - alc_auto_init_digital(codec); - if (spec->unsol_event) - alc_inithook(codec); -} -/* - * Digital-beep handlers - */ -#ifdef CONFIG_SND_HDA_INPUT_BEEP -#define set_beep_amp(spec, nid, idx, dir) \ - ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) - -static const struct snd_pci_quirk beep_white_list[] = { - SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), - SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), - SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), - SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), - SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), - {} -}; + if (spec->autocfg.hp_outs) + alc861_auto_set_output_and_unmute(codec, + spec->autocfg.hp_pins[0], + PIN_HP, + spec->multiout.hp_nid); + if (spec->autocfg.speaker_outs) + alc861_auto_set_output_and_unmute(codec, + spec->autocfg.speaker_pins[0], + PIN_OUT, + spec->multiout.dac_nids[0]); +} -static inline int has_cdefine_beep(struct hda_codec *codec) +static void alc861_auto_init_analog_input(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - const struct snd_pci_quirk *q; - q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list); - if (q) - return q->value; - return spec->cdefine.enable_pcbeep; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (nid >= 0x0c && nid <= 0x11) + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + } } -#else -#define set_beep_amp(spec, nid, idx, dir) /* NOP */ -#define has_cdefine_beep(codec) 0 -#endif /* parse the BIOS configuration and set up the alc_spec */ /* return 1 if successful, 0 if the proper config is not found, * or a negative error code */ -static int alc_parse_auto_config(struct hda_codec *codec, - const hda_nid_t *ignore_nids, - const hda_nid_t *ssid_nids) +static int alc861_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; + static const hda_nid_t alc861_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - ignore_nids); + alc861_ignore); if (err < 0) return err; - if (!spec->autocfg.line_outs) { - if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { - spec->multiout.max_channels = 2; - spec->no_analog = 1; - goto dig_only; - } + if (!spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */ - } - err = alc_auto_fill_dac_nids(codec); - if (err < 0) - return err; - err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids); + + err = alc861_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err; - err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg); + err = alc_auto_add_multi_channel_mode(codec); if (err < 0) return err; - err = alc_auto_create_hp_out(codec); + err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; - err = alc_auto_create_speaker_out(codec); + err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = alc_auto_create_input_ctls(codec); + err = alc861_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; spec->multiout.max_channels = spec->multiout.num_dacs * 2; - dig_only: alc_auto_parse_digital(codec); - if (!spec->no_analog) - alc_remove_invalid_adc_nids(codec); + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc861_auto_init_verbs); - if (ssid_nids) - alc_ssid_check(codec, ssid_nids); + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; - if (!spec->no_analog) { - alc_auto_check_switches(codec); - err = alc_auto_add_mic_boost(codec); - if (err < 0) - return err; - } + spec->adc_nids = alc861_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); + set_capture_mixer(codec); - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); + alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0); return 1; } -static int alc880_parse_auto_config(struct hda_codec *codec) +/* additional initialization for auto-configuration model */ +static void alc861_auto_init(struct hda_codec *codec) { - static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids); + struct alc_spec *spec = codec->spec; + alc861_auto_init_multi_out(codec); + alc861_auto_init_hp_out(codec); + alc861_auto_init_analog_input(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc880_loopbacks[] = { - { 0x0b, HDA_INPUT, 0 }, - { 0x0b, HDA_INPUT, 1 }, - { 0x0b, HDA_INPUT, 2 }, - { 0x0b, HDA_INPUT, 3 }, - { 0x0b, HDA_INPUT, 4 }, +static const struct hda_amp_list alc861_loopbacks[] = { + { 0x15, HDA_INPUT, 0 }, + { 0x15, HDA_INPUT, 1 }, + { 0x15, HDA_INPUT, 2 }, + { 0x15, HDA_INPUT, 3 }, { } /* end */ }; -#endif +#endif + + +/* + * configuration and preset + */ +static const char * const alc861_models[ALC861_MODEL_LAST] = { + [ALC861_3ST] = "3stack", + [ALC660_3ST] = "3stack-660", + [ALC861_3ST_DIG] = "3stack-dig", + [ALC861_6ST_DIG] = "6stack-dig", + [ALC861_UNIWILL_M31] = "uniwill-m31", + [ALC861_TOSHIBA] = "toshiba", + [ALC861_ASUS] = "asus", + [ALC861_ASUS_LAPTOP] = "asus-laptop", + [ALC861_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc861_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), + SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), + SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG), + SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), + /* FIXME: the entry below breaks Toshiba A100 (model=auto works!) + * Any other models that need this preset? + */ + /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */ + SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST), + SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST), + SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), + SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), + SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP), + /* FIXME: the below seems conflict */ + /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */ + SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), + SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), + {} +}; + +static const struct alc_config_preset alc861_presets[] = { + [ALC861_3ST] = { + .mixers = { alc861_3ST_mixer }, + .init_verbs = { alc861_threestack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), + .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_3ST_DIG] = { + .mixers = { alc861_base_mixer }, + .init_verbs = { alc861_threestack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), + .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_6ST_DIG] = { + .mixers = { alc861_base_mixer }, + .init_verbs = { alc861_base_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes), + .channel_mode = alc861_8ch_modes, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC660_3ST] = { + .mixers = { alc861_3ST_mixer }, + .init_verbs = { alc861_threestack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc660_dac_nids), + .dac_nids = alc660_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), + .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_UNIWILL_M31] = { + .mixers = { alc861_uniwill_m31_mixer }, + .init_verbs = { alc861_uniwill_m31_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes), + .channel_mode = alc861_uniwill_m31_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_TOSHIBA] = { + .mixers = { alc861_toshiba_mixer }, + .init_verbs = { alc861_base_init_verbs, + alc861_toshiba_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + .unsol_event = alc861_toshiba_unsol_event, + .init_hook = alc861_toshiba_automute, + }, + [ALC861_ASUS] = { + .mixers = { alc861_asus_mixer }, + .init_verbs = { alc861_asus_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_asus_modes), + .channel_mode = alc861_asus_modes, + .need_dac_fix = 1, + .hp_nid = 0x06, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_ASUS_LAPTOP] = { + .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer }, + .init_verbs = { alc861_asus_init_verbs, + alc861_asus_laptop_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, +}; + +/* Pin config fixes */ +enum { + PINFIX_FSC_AMILO_PI1505, +}; -/* - * board setups - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#define alc_board_config \ - snd_hda_check_board_config -#define alc_board_codec_sid_config \ - snd_hda_check_board_codec_sid_config -#include "alc_quirks.c" -#else -#define alc_board_config(codec, nums, models, tbl) -1 -#define alc_board_codec_sid_config(codec, nums, models, tbl) -1 -#define setup_preset(codec, x) /* NOP */ -#endif +static const struct alc_fixup alc861_fixups[] = { + [PINFIX_FSC_AMILO_PI1505] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x0b, 0x0221101f }, /* HP */ + { 0x0f, 0x90170310 }, /* speaker */ + { } + } + }, +}; -/* - * OK, here we have finally the patch for ALC880 - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc880_quirks.c" -#endif +static const struct snd_pci_quirk alc861_fixup_tbl[] = { + SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), + {} +}; -static int patch_alc880(struct hda_codec *codec) +static int patch_alc861(struct hda_codec *codec) { struct alc_spec *spec; int board_config; @@ -3643,281 +16439,970 @@ static int patch_alc880(struct hda_codec *codec) codec->spec = spec; - spec->mixer_nid = 0x0b; - spec->need_dac_fix = 1; + board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST, + alc861_models, + alc861_cfg_tbl); - board_config = alc_board_config(codec, ALC880_MODEL_LAST, - alc880_models, alc880_cfg_tbl); if (board_config < 0) { printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", codec->chip_name); - board_config = ALC_MODEL_AUTO; + board_config = ALC861_AUTO; + } + + if (board_config == ALC861_AUTO) { + alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); } - if (board_config == ALC_MODEL_AUTO) { + if (board_config == ALC861_AUTO) { /* automatic parse from the BIOS config */ - err = alc880_parse_auto_config(codec); + err = alc861_parse_auto_config(codec); if (err < 0) { alc_free(codec); return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { + } else if (!err) { printk(KERN_INFO "hda_codec: Cannot set up configuration " - "from BIOS. Using 3-stack mode...\n"); - board_config = ALC880_3ST; + "from BIOS. Using base mode...\n"); + board_config = ALC861_3ST_DIG; } -#endif } - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc880_presets[board_config]); - - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + err = snd_hda_attach_beep_device(codec, 0x23); + if (err < 0) { + alc_free(codec); + return err; } - if (!spec->no_analog && !spec->cap_mixer) + if (board_config != ALC861_AUTO) + setup_preset(codec, &alc861_presets[board_config]); + + spec->stream_analog_playback = &alc861_pcm_analog_playback; + spec->stream_analog_capture = &alc861_pcm_analog_capture; + + spec->stream_digital_playback = &alc861_pcm_digital_playback; + spec->stream_digital_capture = &alc861_pcm_digital_capture; + + if (!spec->cap_mixer) set_capture_mixer(codec); + set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - } + spec->vmaster_nid = 0x03; - spec->vmaster_nid = 0x0c; + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + if (board_config == ALC861_AUTO) { + spec->init_hook = alc861_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->power_hook = alc_power_eapd; +#endif + } #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) - spec->loopback.amplist = alc880_loopbacks; + spec->loopback.amplist = alc861_loopbacks; #endif return 0; } +/* + * ALC861-VD support + * + * Based on ALC882 + * + * In addition, an independent DAC + */ +#define ALC861VD_DIGOUT_NID 0x06 + +static const hda_nid_t alc861vd_dac_nids[4] = { + /* front, surr, clfe, side surr */ + 0x02, 0x03, 0x04, 0x05 +}; + +/* dac_nids for ALC660vd are in a different order - according to + * Realtek's driver. + * This should probably result in a different mixer for 6stack models + * of ALC660vd codecs, but for now there is only 3stack mixer + * - and it is the same as in 861vd. + * adc_nids in ALC660vd are (is) the same as in 861vd + */ +static const hda_nid_t alc660vd_dac_nids[3] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x04, 0x03 +}; + +static const hda_nid_t alc861vd_adc_nids[1] = { + /* ADC0 */ + 0x09, +}; + +static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 }; + +/* input MUX */ +/* FIXME: should be a matrix-type input source selection */ +static const struct hda_input_mux alc861vd_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc861vd_dallas_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + }, +}; + +static const struct hda_input_mux alc861vd_hp_capture_source = { + .num_items = 2, + .items = { + { "Front Mic", 0x0 }, + { "ATAPI Mic", 0x1 }, + }, +}; /* - * ALC260 support + * 2ch mode */ -static int alc260_parse_auto_config(struct hda_codec *codec) +static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { + { 2, NULL } +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc861vd_6stack_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc861vd_6stack_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +static const struct hda_channel_mode alc861vd_6stack_modes[2] = { + { 6, alc861vd_6stack_ch6_init }, + { 8, alc861vd_6stack_ch8_init }, +}; + +static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 + * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b + */ +static const struct snd_kcontrol_new alc861vd_6st_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + + HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + { } /* end */ +}; + +static const struct snd_kcontrol_new alc861vd_3st_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + { } /* end */ +}; + +static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/ + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + { } /* end */ +}; + +/* Pin assignment: Speaker=0x14, HP = 0x15, + * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d + */ +static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +/* Pin assignment: Speaker=0x14, Line-out = 0x15, + * Front Mic=0x18, ATAPI Mic = 0x19, + */ +static const struct snd_kcontrol_new alc861vd_hp_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + { } /* end */ +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc861vd_volume_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of + * the analog-loopback mixer widget + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output mixers (0x02 - 0x05) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +/* + * 3-stack pin configuration: + * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b + */ +static const struct hda_verb alc861vd_3stack_init_verbs[] = { + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * 6-stack pin configuration: + */ +static const struct hda_verb alc861vd_6stack_init_verbs[] = { + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Rear Pin: output 1 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* Side Pin: output 3 (0x0f) */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +static const struct hda_verb alc861vd_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc660vd_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {} +}; + +static void alc861vd_lenovo_setup(struct hda_codec *codec) { - static const hda_nid_t alc260_ignore[] = { 0x17, 0 }; - static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 }; - return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids); + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc260_loopbacks[] = { - { 0x07, HDA_INPUT, 0 }, - { 0x07, HDA_INPUT, 1 }, - { 0x07, HDA_INPUT, 2 }, - { 0x07, HDA_INPUT, 3 }, - { 0x07, HDA_INPUT, 4 }, +static void alc861vd_lenovo_init_hook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc88x_simple_mic_automute(codec); +} + +static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_MIC_EVENT: + alc88x_simple_mic_automute(codec); + break; + default: + alc_sku_unsol_event(codec, res); + break; + } +} + +static const struct hda_verb alc861vd_dallas_verbs[] = { + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + { } /* end */ }; + +/* toggle speaker-output according to the hp-jack state */ +static void alc861vd_dallas_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc861vd_loopbacks alc880_loopbacks #endif +/* pcm configuration: identical with ALC880 */ +#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback +#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture +#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback +#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture + /* - * Pin config fixes + * configuration and preset */ -enum { - PINFIX_HP_DC5750, +static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = { + [ALC660VD_3ST] = "3stack-660", + [ALC660VD_3ST_DIG] = "3stack-660-digout", + [ALC660VD_ASUS_V1S] = "asus-v1s", + [ALC861VD_3ST] = "3stack", + [ALC861VD_3ST_DIG] = "3stack-digout", + [ALC861VD_6ST_DIG] = "6stack-digout", + [ALC861VD_LENOVO] = "lenovo", + [ALC861VD_DALLAS] = "dallas", + [ALC861VD_HP] = "hp", + [ALC861VD_AUTO] = "auto", }; -static const struct alc_fixup alc260_fixups[] = { - [PINFIX_HP_DC5750] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x11, 0x90130110 }, /* speaker */ - { } - } +static const struct snd_pci_quirk alc861vd_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), + SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), + SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), + /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */ + SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S), + SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), + SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), + SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), + /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ + SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS), + SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), + {} +}; + +static const struct alc_config_preset alc861vd_presets[] = { + [ALC660VD_3ST] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC660VD_3ST_DIG] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_3ST] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_3ST_DIG] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_6ST_DIG] = { + .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_6stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes), + .channel_mode = alc861vd_6stack_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_LENOVO] = { + .mixers = { alc861vd_lenovo_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs, + alc861vd_eapd_verbs, + alc861vd_lenovo_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + .unsol_event = alc861vd_lenovo_unsol_event, + .setup = alc861vd_lenovo_setup, + .init_hook = alc861vd_lenovo_init_hook, + }, + [ALC861VD_DALLAS] = { + .mixers = { alc861vd_dallas_mixer }, + .init_verbs = { alc861vd_dallas_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_dallas_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc861vd_dallas_setup, + .init_hook = alc_hp_automute, + }, + [ALC861VD_HP] = { + .mixers = { alc861vd_hp_mixer }, + .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_hp_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc861vd_dallas_setup, + .init_hook = alc_hp_automute, + }, + [ALC660VD_ASUS_V1S] = { + .mixers = { alc861vd_lenovo_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs, + alc861vd_eapd_verbs, + alc861vd_lenovo_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + .unsol_event = alc861vd_lenovo_unsol_event, + .setup = alc861vd_lenovo_setup, + .init_hook = alc861vd_lenovo_init_hook, }, }; -static const struct snd_pci_quirk alc260_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750), - {} -}; +/* + * BIOS auto configuration + */ +static int alc861vd_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0); +} + + +static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, int dac_idx) +{ + alc_set_pin_output(codec, nid, pin_type); +} + +static void alc861vd_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i <= HDA_SIDE; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + if (nid) + alc861vd_auto_set_output_and_unmute(codec, nid, + pin_type, i); + } +} -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc260_quirks.c" -#endif -static int patch_alc260(struct hda_codec *codec) +static void alc861vd_auto_init_hp_out(struct hda_codec *codec) { - struct alc_spec *spec; - int err, board_config; + struct alc_spec *spec = codec->spec; + hda_nid_t pin; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + pin = spec->autocfg.hp_pins[0]; + if (pin) /* connect to front and use dac 0 */ + alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); + pin = spec->autocfg.speaker_pins[0]; + if (pin) + alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); +} - codec->spec = spec; +#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID - spec->mixer_nid = 0x07; +static void alc861vd_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; - board_config = alc_board_config(codec, ALC260_MODEL_LAST, - alc260_models, alc260_cfg_tbl); - if (board_config < 0) { - snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (alc_is_input_pin(codec, nid)) { + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + if (nid != ALC861VD_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } } +} - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } +#define alc861vd_auto_init_input_src alc882_auto_init_input_src - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc260_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC260_BASIC; - } -#endif - } +#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02) +#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c) - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc260_presets[board_config]); +/* add playback controls from the parsed DAC table */ +/* Based on ALC880 version. But ALC861VD has separate, + * different NIDs for mute/unmute switch and volume control */ +static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static const char * const chname[4] = { + "Front", "Surround", "CLFE", "Side" + }; + const char *pfx = alc_get_line_out_pfx(spec, true); + hda_nid_t nid_v, nid_s; + int i, err, noutputs; - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { + if (!spec->multiout.dac_nids[i]) + continue; + nid_v = alc861vd_idx_to_mixer_vol( + alc880_dac_to_idx( + spec->multiout.dac_nids[i])); + nid_s = alc861vd_idx_to_mixer_switch( + alc880_dac_to_idx( + spec->multiout.dac_nids[i])); + + if (!pfx && i == 2) { + /* Center/LFE */ + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "Center", + HDA_COMPOSE_AMP_VAL(nid_v, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "LFE", + HDA_COMPOSE_AMP_VAL(nid_v, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "Center", + HDA_COMPOSE_AMP_VAL(nid_s, 1, 2, + HDA_INPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "LFE", + HDA_COMPOSE_AMP_VAL(nid_s, 2, 2, + HDA_INPUT)); + if (err < 0) + return err; + } else { + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + name, index, + HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + name, index, + HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, + HDA_INPUT)); + if (err < 0) + return err; + } } + return 0; +} - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); +/* add playback controls for speaker and HP outputs */ +/* Based on ALC880 version. But ALC861VD has separate, + * different NIDs for mute/unmute switch and volume control */ +static int alc861vd_auto_create_extra_out(struct alc_spec *spec, + hda_nid_t pin, const char *pfx) +{ + hda_nid_t nid_v, nid_s; + int err; - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); + if (!pin) + return 0; + + if (alc880_is_fixed_pin(pin)) { + nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); + /* specify the DAC as the extra output */ + if (!spec->multiout.hp_nid) + spec->multiout.hp_nid = nid_v; + else + spec->multiout.extra_out_nid[0] = nid_v; + /* control HP volume/switch on the output mixer amp */ + nid_v = alc861vd_idx_to_mixer_vol( + alc880_fixed_pin_idx(pin)); + nid_s = alc861vd_idx_to_mixer_switch( + alc880_fixed_pin_idx(pin)); + + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, + HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT)); + if (err < 0) + return err; + } else if (alc880_is_multi_pin(pin)) { + /* set manual connection */ + /* we have only a switch on HP-out PIN */ + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) return err; - } - set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); } + return 0; +} - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +/* parse the BIOS configuration and set up the alc_spec + * return 1 if successful, 0 if the proper config is not found, + * or a negative error code + * Based on ALC880 version - had to change it to override + * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */ +static int alc861vd_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; - spec->vmaster_nid = 0x08; + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc861vd_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) + return 0; /* can't find valid BIOS pin config */ - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - spec->shutup = alc_eapd_shutup; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc260_loopbacks; -#endif + err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; + err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc861vd_auto_create_extra_out(spec, + spec->autocfg.speaker_pins[0], + "Speaker"); + if (err < 0) + return err; + err = alc861vd_auto_create_extra_out(spec, + spec->autocfg.hp_pins[0], + "Headphone"); + if (err < 0) + return err; + err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; - return 0; -} + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + alc_auto_parse_digital(codec); -/* - * ALC882/883/885/888/889 support - * - * ALC882 is almost identical with ALC880 but has cleaner and more flexible - * configuration. Each pin widget can choose any input DACs and a mixer. - * Each ADC is connected from a mixer of all inputs. This makes possible - * 6-channel independent captures. - * - * In addition, an independent DAC for the multi-playback (not used in this - * driver yet). - */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc882_loopbacks alc880_loopbacks -#endif + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc861vd_volume_init_verbs); + + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + return 1; +} + +/* additional initialization for auto-configuration model */ +static void alc861vd_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc861vd_auto_init_multi_out(codec); + alc861vd_auto_init_hp_out(codec); + alc861vd_auto_init_analog_input(codec); + alc861vd_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} -/* - * Pin config fixes - */ enum { - PINFIX_ABIT_AW9D_MAX, - PINFIX_LENOVO_Y530, - PINFIX_PB_M5210, - PINFIX_ACER_ASPIRE_7736, + ALC660VD_FIX_ASUS_GPIO1 }; -static const struct alc_fixup alc882_fixups[] = { - [PINFIX_ABIT_AW9D_MAX] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x15, 0x01080104 }, /* side */ - { 0x16, 0x01011012 }, /* rear */ - { 0x17, 0x01016011 }, /* clfe */ - { } - } - }, - [PINFIX_LENOVO_Y530] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x15, 0x99130112 }, /* rear int speakers */ - { 0x16, 0x99130111 }, /* subwoofer */ - { } - } - }, - [PINFIX_PB_M5210] = { +/* reset GPIO1 */ +static const struct alc_fixup alc861vd_fixups[] = { + [ALC660VD_FIX_ASUS_GPIO1] = { .type = ALC_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, - {} + {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + { } } }, - [PINFIX_ACER_ASPIRE_7736] = { - .type = ALC_FIXUP_SKU, - .v.sku = ALC_FIXUP_SKU_IGNORE, - }, }; -static const struct snd_pci_quirk alc882_fixup_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530), - SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), - SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736), +static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), {} }; -/* - * BIOS auto configuration - */ -/* almost identical with ALC880 parser... */ -static int alc882_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc882_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids); -} - -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc882_quirks.c" -#endif - -static int patch_alc882(struct hda_codec *codec) +static int patch_alc861vd(struct hda_codec *codec) { struct alc_spec *spec; int err, board_config; @@ -3928,1126 +17413,2030 @@ static int patch_alc882(struct hda_codec *codec) codec->spec = spec; - spec->mixer_nid = 0x0b; - - switch (codec->vendor_id) { - case 0x10ec0882: - case 0x10ec0885: - break; - default: - /* ALC883 and variants */ - alc_fix_pll_init(codec, 0x20, 0x0a, 10); - break; - } - - board_config = alc_board_config(codec, ALC882_MODEL_LAST, - alc882_models, alc882_cfg_tbl); - - if (board_config < 0) - board_config = alc_board_codec_sid_config(codec, - ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl); + board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST, + alc861vd_models, + alc861vd_cfg_tbl); - if (board_config < 0) { + if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) { printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", codec->chip_name); - board_config = ALC_MODEL_AUTO; + board_config = ALC861VD_AUTO; } - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); + if (board_config == ALC861VD_AUTO) { + alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); } - alc_auto_parse_customize_define(codec); - - if (board_config == ALC_MODEL_AUTO) { + if (board_config == ALC861VD_AUTO) { /* automatic parse from the BIOS config */ - err = alc882_parse_auto_config(codec); + err = alc861vd_parse_auto_config(codec); if (err < 0) { alc_free(codec); return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { + } else if (!err) { printk(KERN_INFO "hda_codec: Cannot set up configuration " "from BIOS. Using base mode...\n"); - board_config = ALC882_3ST_DIG; + board_config = ALC861VD_3ST; } -#endif } - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc882_presets[board_config]); + err = snd_hda_attach_beep_device(codec, 0x23); + if (err < 0) { + alc_free(codec); + return err; + } - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + if (board_config != ALC861VD_AUTO) + setup_preset(codec, &alc861vd_presets[board_config]); + + if (codec->vendor_id == 0x10ec0660) { + /* always turn on EAPD */ + add_verb(spec, alc660vd_eapd_verbs); } - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + spec->stream_analog_playback = &alc861vd_pcm_analog_playback; + spec->stream_analog_capture = &alc861vd_pcm_analog_capture; - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + spec->stream_digital_playback = &alc861vd_pcm_digital_playback; + spec->stream_digital_capture = &alc861vd_pcm_digital_capture; + + if (!spec->adc_nids) { + spec->adc_nids = alc861vd_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc861vd_capsrc_nids; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + set_capture_mixer(codec); + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - spec->vmaster_nid = 0x0c; + spec->vmaster_nid = 0x02; + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - alc_init_jacks(codec); + if (board_config == ALC861VD_AUTO) + spec->init_hook = alc861vd_auto_init; + spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) - spec->loopback.amplist = alc882_loopbacks; + spec->loopback.amplist = alc861vd_loopbacks; #endif return 0; } - /* - * ALC262 support + * ALC662 support + * + * ALC662 is almost identical with ALC880 but has cleaner and more flexible + * configuration. Each pin widget can choose any input DACs and a mixer. + * Each ADC is connected from a mixer of all inputs. This makes possible + * 6-channel independent captures. + * + * In addition, an independent DAC for the multi-playback (not used in this + * driver yet). */ -static int alc262_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc262_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids); -} +#define ALC662_DIGOUT_NID 0x06 +#define ALC662_DIGIN_NID 0x0a -/* - * Pin config fixes - */ -enum { - PINFIX_FSC_H270, - PINFIX_HP_Z200, +static const hda_nid_t alc662_dac_nids[3] = { + /* front, rear, clfe */ + 0x02, 0x03, 0x04 }; -static const struct alc_fixup alc262_fixups[] = { - [PINFIX_FSC_H270] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x0221142f }, /* front HP */ - { 0x1b, 0x0121141f }, /* rear HP */ - { } - } - }, - [PINFIX_HP_Z200] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x16, 0x99130120 }, /* internal speaker */ - { } - } +static const hda_nid_t alc272_dac_nids[2] = { + 0x02, 0x03 +}; + +static const hda_nid_t alc662_adc_nids[2] = { + /* ADC1-2 */ + 0x09, 0x08 +}; + +static const hda_nid_t alc272_adc_nids[1] = { + /* ADC1-2 */ + 0x08, +}; + +static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; +static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; + + +/* input MUX */ +/* FIXME: should be a matrix-type input source selection */ +static const struct hda_input_mux alc662_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, }, }; -static const struct snd_pci_quirk alc262_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200), - SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270), - {} +static const struct hda_input_mux alc662_lenovo_101e_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "Line", 0x2 }, + }, }; +static const struct hda_input_mux alc663_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc262_loopbacks alc880_loopbacks +#if 0 /* set to 1 for testing other input sources below */ +static const struct hda_input_mux alc272_nc10_capture_source = { + .num_items = 16, + .items = { + { "Autoselect Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "In-0x02", 0x2 }, + { "In-0x03", 0x3 }, + { "In-0x04", 0x4 }, + { "In-0x05", 0x5 }, + { "In-0x06", 0x6 }, + { "In-0x07", 0x7 }, + { "In-0x08", 0x8 }, + { "In-0x09", 0x9 }, + { "In-0x0a", 0x0a }, + { "In-0x0b", 0x0b }, + { "In-0x0c", 0x0c }, + { "In-0x0d", 0x0d }, + { "In-0x0e", 0x0e }, + { "In-0x0f", 0x0f }, + }, +}; #endif /* + * 2ch mode */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc262_quirks.c" -#endif +static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = { + { 2, NULL } +}; -static int patch_alc262(struct hda_codec *codec) -{ - struct alc_spec *spec; - int board_config; - int err; +/* + * 2ch mode + */ +static const struct hda_verb alc662_3ST_ch2_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; +/* + * 6ch mode + */ +static const struct hda_verb alc662_3ST_ch6_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; - codec->spec = spec; +static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = { + { 2, alc662_3ST_ch2_init }, + { 6, alc662_3ST_ch6_init }, +}; - spec->mixer_nid = 0x0b; +/* + * 2ch mode + */ +static const struct hda_verb alc662_sixstack_ch6_init[] = { + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; -#if 0 - /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is - * under-run - */ - { - int tmp; - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); - } -#endif - alc_auto_parse_customize_define(codec); +/* + * 6ch mode + */ +static const struct hda_verb alc662_sixstack_ch8_init[] = { + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; - alc_fix_pll_init(codec, 0x20, 0x0a, 10); +static const struct hda_channel_mode alc662_5stack_modes[2] = { + { 2, alc662_sixstack_ch6_init }, + { 6, alc662_sixstack_ch8_init }, +}; - board_config = alc_board_config(codec, ALC262_MODEL_LAST, - alc262_models, alc262_cfg_tbl); +/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 + * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b + */ - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } +static const struct snd_kcontrol_new alc662_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + /*Input mixer control */ + HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), + { } /* end */ +}; - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } +static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc262_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC262_BASIC; - } -#endif - } +static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc262_presets[board_config]); +static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } +static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - } + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; - spec->vmaster_nid = 0x0c; +static const struct hda_bind_ctls alc663_asus_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), + 0 + }, +}; - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - spec->shutup = alc_eapd_shutup; +static const struct hda_bind_ctls alc663_asus_one_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + 0 + }, +}; - alc_init_jacks(codec); -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc262_loopbacks; -#endif +static const struct snd_kcontrol_new alc663_m51va_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; - return 0; -} +static const struct hda_bind_ctls alc663_asus_tree_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + 0 + }, +}; -/* - * ALC268 - */ -/* bind Beep switches of both NID 0x0f and 0x10 */ -static const struct hda_bind_ctls alc268_bind_beep_sw = { +static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_four_bind_switch = { .ops = &snd_hda_bind_sw, .values = { - HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc662_1bjd_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT), 0 }, }; -static const struct snd_kcontrol_new alc268_beep_mixer[] = { - HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT), - HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw), +static const struct hda_bind_ctls alc663_asus_two_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", + &alc663_asus_two_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_g71v_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_g50v_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_mode7_mixer[] = { + HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), + HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), + HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_mode8_mixer[] = { + HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), + HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), + HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + + +static const struct snd_kcontrol_new alc662_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc662_init_verbs[] = { + /* ADC: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Rear Pin: output 1 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { } }; -/* set PCBEEP vol = 0, mute connections */ -static const struct hda_verb alc268_beep_init_verbs[] = { - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +static const struct hda_verb alc662_eapd_init_verbs[] = { + /* always trun on EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -/* - * BIOS auto configuration - */ -static int alc268_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - struct alc_spec *spec = codec->spec; - int err = alc_parse_auto_config(codec, NULL, alc268_ssids); - if (err > 0) { - if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) { - add_mixer(spec, alc268_beep_mixer); - add_verb(spec, alc268_beep_init_verbs); - } - } - return err; -} - -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc268_quirks.c" -#endif +static const struct hda_verb alc662_sue_init_verbs[] = { + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, + {} +}; -static int patch_alc268(struct hda_codec *codec) -{ - struct alc_spec *spec; - int board_config; - int i, has_beep, err; +static const struct hda_verb alc662_eeepc_sue_init_verbs[] = { + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; +/* Set Unsolicited Event*/ +static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - codec->spec = spec; +static const struct hda_verb alc663_m51va_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - /* ALC268 has no aa-loopback mixer */ +static const struct hda_verb alc663_21jd_amic_init_verbs[] = { + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - board_config = alc_board_config(codec, ALC268_MODEL_LAST, - alc268_models, alc268_cfg_tbl); +static const struct hda_verb alc662_1bjd_amic_init_verbs[] = { + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - if (board_config < 0) - board_config = alc_board_codec_sid_config(codec, - ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl); +static const struct hda_verb alc663_15jd_amic_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } +static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc268_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC268_3ST; - } -#endif - } +static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc268_presets[board_config]); +static const struct hda_verb alc663_g71v_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ + /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ - has_beep = 0; - for (i = 0; i < spec->num_mixers; i++) { - if (spec->mixers[i] == alc268_beep_mixer) { - has_beep = 1; - break; - } - } + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - if (has_beep) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) - /* override the amp caps for beep generator */ - snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, - (0x0c << AC_AMPCAP_OFFSET_SHIFT) | - (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (0 << AC_AMPCAP_MUTE_SHIFT)); - } + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, + {} +}; - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } +static const struct hda_verb alc663_g50v_init_verbs[] = { + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - spec->vmaster_nid = 0x02; +static const struct hda_verb alc662_ecs_init_verbs[] = { + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - spec->shutup = alc_eapd_shutup; +static const struct hda_verb alc272_dell_zm1_init_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - alc_init_jacks(codec); +static const struct hda_verb alc272_dell_init_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; - return 0; -} +static const struct hda_verb alc663_mode7_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; -/* - * ALC269 - */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc269_loopbacks alc880_loopbacks -#endif +static const struct hda_verb alc663_mode8_init_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; -static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc_playback_pcm_open, - .prepare = alc_playback_pcm_prepare, - .cleanup = alc_playback_pcm_cleanup - }, +static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + { } /* end */ }; -static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ - /* NID is set in alc_build_pcms */ +static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { } /* end */ }; -#ifdef CONFIG_SND_HDA_POWER_SAVE -static int alc269_mic2_for_mute_led(struct hda_codec *codec) +static void alc662_lenovo_101e_setup(struct hda_codec *codec) { - switch (codec->subsystem_id) { - case 0x103c1586: - return 1; - } - return 0; + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) +static void alc662_eeepc_setup(struct hda_codec *codec) { - /* update mute-LED according to the speaker mute state */ - if (nid == 0x01 || nid == 0x14) { - int pinval; - if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) & - HDA_AMP_MUTE) - pinval = 0x24; - else - pinval = 0x20; - /* mic2 vref pin is used for mute LED control */ - snd_hda_codec_update_cache(codec, 0x19, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinval); - } - return alc_check_power_status(codec, nid); -} -#endif /* CONFIG_SND_HDA_POWER_SAVE */ + struct alc_spec *spec = codec->spec; -/* different alc269-variants */ -enum { - ALC269_TYPE_ALC269VA, - ALC269_TYPE_ALC269VB, - ALC269_TYPE_ALC269VC, -}; + alc262_hippo1_setup(codec); + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} -/* - * BIOS auto configuration - */ -static int alc269_parse_auto_config(struct hda_codec *codec) +static void alc662_eeepc_ep20_setup(struct hda_codec *codec) { - static const hda_nid_t alc269_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 }; - static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 }; struct alc_spec *spec = codec->spec; - const hda_nid_t *ssids = spec->codec_variant == ALC269_TYPE_ALC269VA ? - alc269va_ssids : alc269_ssids; - return alc_parse_auto_config(codec, alc269_ignore, ssids); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) +static void alc663_m51va_setup(struct hda_codec *codec) { - int val = alc_read_coef_idx(codec, 0x04); - if (power_up) - val |= 1 << 11; - else - val &= ~(1 << 11); - alc_write_coef_idx(codec, 0x04, val); + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; } -static void alc269_shutup(struct hda_codec *codec) +/* ***************** Mode1 ******************************/ +static void alc663_mode1_setup(struct hda_codec *codec) { - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) - alc269_toggle_power_output(codec, 0); - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { - alc269_toggle_power_output(codec, 0); - msleep(150); - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#ifdef SND_HDA_NEEDS_RESUME -static int alc269_resume(struct hda_codec *codec) +/* ***************** Mode2 ******************************/ +static void alc662_mode2_setup(struct hda_codec *codec) { - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { - alc269_toggle_power_output(codec, 0); - msleep(150); - } - - codec->patch_ops.init(codec); - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { - alc269_toggle_power_output(codec, 1); - msleep(200); - } - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) - alc269_toggle_power_output(codec, 1); - - snd_hda_codec_resume_amp(codec); - snd_hda_codec_resume_cache(codec); - hda_call_check_power_status(codec, 0x01); - return 0; + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#endif /* SND_HDA_NEEDS_RESUME */ -static void alc269_fixup_hweq(struct hda_codec *codec, - const struct alc_fixup *fix, int action) +/* ***************** Mode3 ******************************/ +static void alc663_mode3_setup(struct hda_codec *codec) { - int coef; + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} - if (action != ALC_FIXUP_ACT_INIT) - return; - coef = alc_read_coef_idx(codec, 0x1e); - alc_write_coef_idx(codec, 0x1e, coef | 0x80); +/* ***************** Mode4 ******************************/ +static void alc663_mode4_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute_mixer_nid[1] = 0x0e; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -static void alc271_fixup_dmic(struct hda_codec *codec, - const struct alc_fixup *fix, int action) +/* ***************** Mode5 ******************************/ +static void alc663_mode5_setup(struct hda_codec *codec) { - static const struct hda_verb verbs[] = { - {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, - {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, - {} - }; - unsigned int cfg; + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute_mixer_nid[1] = 0x0e; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} - if (strcmp(codec->chip_name, "ALC271X")) - return; - cfg = snd_hda_codec_get_pincfg(codec, 0x12); - if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED) - snd_hda_sequence_write(codec, verbs); +/* ***************** Mode6 ******************************/ +static void alc663_mode6_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -static void alc269_fixup_pcm_44k(struct hda_codec *codec, - const struct alc_fixup *fix, int action) +/* ***************** Mode7 ******************************/ +static void alc663_mode7_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} - if (action != ALC_FIXUP_ACT_PROBE) - return; +/* ***************** Mode8 ******************************/ +static void alc663_mode8_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.hp_pins[1] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; +} - /* Due to a hardware problem on Lenovo Ideadpad, we need to - * fix the sample rate of analog I/O to 44.1kHz - */ - spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; - spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; +static void alc663_g71v_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.line_out_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; } -enum { - ALC269_FIXUP_SONY_VAIO, - ALC275_FIXUP_SONY_VAIO_GPIO2, - ALC269_FIXUP_DELL_M101Z, - ALC269_FIXUP_SKU_IGNORE, - ALC269_FIXUP_ASUS_G73JW, - ALC269_FIXUP_LENOVO_EAPD, - ALC275_FIXUP_SONY_HWEQ, - ALC271_FIXUP_DMIC, - ALC269_FIXUP_PCM_44K, +#define alc663_g50v_setup alc663_m51va_setup + +static const struct snd_kcontrol_new alc662_ecs_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + + HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ }; -static const struct alc_fixup alc269_fixups[] = { - [ALC269_FIXUP_SONY_VAIO] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, - {} - } +static const struct snd_kcontrol_new alc272_nc10_mixer[] = { + /* Master Playback automatically created from Speaker and Headphone */ + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc662_loopbacks alc880_loopbacks +#endif + + +/* pcm configuration: identical with ALC880 */ +#define alc662_pcm_analog_playback alc880_pcm_analog_playback +#define alc662_pcm_analog_capture alc880_pcm_analog_capture +#define alc662_pcm_digital_playback alc880_pcm_digital_playback +#define alc662_pcm_digital_capture alc880_pcm_digital_capture + +/* + * configuration and preset + */ +static const char * const alc662_models[ALC662_MODEL_LAST] = { + [ALC662_3ST_2ch_DIG] = "3stack-dig", + [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", + [ALC662_3ST_6ch] = "3stack-6ch", + [ALC662_5ST_DIG] = "5stack-dig", + [ALC662_LENOVO_101E] = "lenovo-101e", + [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", + [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", + [ALC662_ECS] = "ecs", + [ALC663_ASUS_M51VA] = "m51va", + [ALC663_ASUS_G71V] = "g71v", + [ALC663_ASUS_H13] = "h13", + [ALC663_ASUS_G50V] = "g50v", + [ALC663_ASUS_MODE1] = "asus-mode1", + [ALC662_ASUS_MODE2] = "asus-mode2", + [ALC663_ASUS_MODE3] = "asus-mode3", + [ALC663_ASUS_MODE4] = "asus-mode4", + [ALC663_ASUS_MODE5] = "asus-mode5", + [ALC663_ASUS_MODE6] = "asus-mode6", + [ALC663_ASUS_MODE7] = "asus-mode7", + [ALC663_ASUS_MODE8] = "asus-mode8", + [ALC272_DELL] = "dell", + [ALC272_DELL_ZM1] = "dell-zm1", + [ALC272_SAMSUNG_NC10] = "samsung-nc10", + [ALC662_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc662_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), + SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL), + SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), + SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7), + SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7), + SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8), + SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA), + SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5), + SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), + /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/ + SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V), + /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/ + SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA), + SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4), + SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), + SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), + SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), + SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO), + SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13), + SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), + SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), + SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x", + ALC663_ASUS_H13), + SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E), + {} +}; + +static const struct alc_config_preset alc662_presets[] = { + [ALC662_3ST_2ch_DIG] = { + .mixers = { alc662_3ST_2ch_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .dig_in_nid = ALC662_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_capture_source, }, - [ALC275_FIXUP_SONY_VAIO_GPIO2] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x01, AC_VERB_SET_GPIO_MASK, 0x04}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - { } - }, - .chained = true, - .chain_id = ALC269_FIXUP_SONY_VAIO + [ALC662_3ST_6ch_DIG] = { + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .dig_in_nid = ALC662_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc662_capture_source, }, - [ALC269_FIXUP_DELL_M101Z] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* Enables internal speaker */ - {0x20, AC_VERB_SET_COEF_INDEX, 13}, - {0x20, AC_VERB_SET_PROC_COEF, 0x4040}, - {} - } + [ALC662_3ST_6ch] = { + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc662_capture_source, }, - [ALC269_FIXUP_SKU_IGNORE] = { - .type = ALC_FIXUP_SKU, - .v.sku = ALC_FIXUP_SKU_IGNORE, + [ALC662_5ST_DIG] = { + .mixers = { alc662_base_mixer, alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .dig_in_nid = ALC662_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes), + .channel_mode = alc662_5stack_modes, + .input_mux = &alc662_capture_source, }, - [ALC269_FIXUP_ASUS_G73JW] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x17, 0x99130111 }, /* subwoofer */ - { } - } + [ALC662_LENOVO_101E] = { + .mixers = { alc662_lenovo_101e_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_lenovo_101e_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_lenovo_101e_setup, + .init_hook = alc_inithook, }, - [ALC269_FIXUP_LENOVO_EAPD] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, - {} - } + [ALC662_ASUS_EEEPC_P701] = { + .mixers = { alc662_eeepc_p701_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_eeepc_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_eeepc_setup, + .init_hook = alc_inithook, }, - [ALC275_FIXUP_SONY_HWEQ] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc269_fixup_hweq, - .chained = true, - .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 + [ALC662_ASUS_EEEPC_EP20] = { + .mixers = { alc662_eeepc_ep20_mixer, + alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_eeepc_ep20_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .input_mux = &alc662_lenovo_101e_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_eeepc_ep20_setup, + .init_hook = alc_inithook, }, - [ALC271_FIXUP_DMIC] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc271_fixup_dmic, + [ALC662_ECS] = { + .mixers = { alc662_ecs_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_ecs_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_eeepc_setup, + .init_hook = alc_inithook, }, - [ALC269_FIXUP_PCM_44K] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc269_fixup_pcm_44k, + [ALC663_ASUS_M51VA] = { + .mixers = { alc663_m51va_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_m51va_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_G71V] = { + .mixers = { alc663_g71v_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g71v_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_g71v_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_H13] = { + .mixers = { alc663_m51va_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .setup = alc663_m51va_setup, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_G50V] = { + .mixers = { alc663_g50v_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g50v_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .input_mux = &alc663_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_g50v_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE1] = { + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_21jd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode1_setup, + .init_hook = alc_inithook, + }, + [ALC662_ASUS_MODE2] = { + .mixers = { alc662_1bjd_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_1bjd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_mode2_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE3] = { + .mixers = { alc663_two_hp_m1_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_two_hp_amic_m1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode3_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE4] = { + .mixers = { alc663_asus_21jd_clfe_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_21jd_amic_init_verbs}, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode4_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE5] = { + .mixers = { alc663_asus_15jd_clfe_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_15jd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode5_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE6] = { + .mixers = { alc663_two_hp_m2_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_two_hp_amic_m2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode6_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE7] = { + .mixers = { alc663_mode7_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_mode7_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode7_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE8] = { + .mixers = { alc663_mode8_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_mode8_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode8_setup, + .init_hook = alc_inithook, + }, + [ALC272_DELL] = { + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc272_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_init_verbs }, + .num_dacs = ARRAY_SIZE(alc272_dac_nids), + .dac_nids = alc272_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .adc_nids = alc272_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), + .capsrc_nids = alc272_capsrc_nids, + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_m51va_setup, + .init_hook = alc_inithook, + }, + [ALC272_DELL_ZM1] = { + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_zm1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc272_dac_nids), + .dac_nids = alc272_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .adc_nids = alc662_adc_nids, + .num_adc_nids = 1, + .capsrc_nids = alc662_capsrc_nids, + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_m51va_setup, + .init_hook = alc_inithook, + }, + [ALC272_SAMSUNG_NC10] = { + .mixers = { alc272_nc10_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_21jd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc272_dac_nids), + .dac_nids = alc272_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + /*.input_mux = &alc272_nc10_capture_source,*/ + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode4_setup, + .init_hook = alc_inithook, }, }; -static const struct snd_pci_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), - SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), - SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), - SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), - SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), - SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), - SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), - SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), - SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), - {} -}; +/* + * BIOS auto configuration + */ -static int alc269_fill_coef(struct hda_codec *codec) +/* convert from MIX nid to DAC */ +static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid) { - int val; - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) { - alc_write_coef_idx(codec, 0xf, 0x960b); - alc_write_coef_idx(codec, 0xe, 0x8817); - } - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) { - alc_write_coef_idx(codec, 0xf, 0x960b); - alc_write_coef_idx(codec, 0xe, 0x8814); - } - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { - val = alc_read_coef_idx(codec, 0x04); - /* Power up output pin */ - alc_write_coef_idx(codec, 0x04, val | (1<<11)); - } + hda_nid_t list[5]; + int i, num; - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { - val = alc_read_coef_idx(codec, 0xd); - if ((val & 0x0c00) >> 10 != 0x1) { - /* Capless ramp up clock control */ - alc_write_coef_idx(codec, 0xd, val | (1<<10)); - } - val = alc_read_coef_idx(codec, 0x17); - if ((val & 0x01c0) >> 6 != 0x4) { - /* Class D power on reset */ - alc_write_coef_idx(codec, 0x17, val | (1<<7)); - } + num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list)); + for (i = 0; i < num; i++) { + if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT) + return list[i]; } - - val = alc_read_coef_idx(codec, 0xd); /* Class D */ - alc_write_coef_idx(codec, 0xd, val | (1<<14)); - - val = alc_read_coef_idx(codec, 0x4); /* HP */ - alc_write_coef_idx(codec, 0x4, val | (1<<11)); - return 0; } -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc269_quirks.c" -#endif - -static int patch_alc269(struct hda_codec *codec) +/* go down to the selector widget before the mixer */ +static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin) { - struct alc_spec *spec; - int board_config, coef; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - spec->mixer_nid = 0x0b; - - alc_auto_parse_customize_define(codec); - - if (codec->vendor_id == 0x10ec0269) { - spec->codec_variant = ALC269_TYPE_ALC269VA; - coef = alc_read_coef_idx(codec, 0); - if ((coef & 0x00f0) == 0x0010) { - if (codec->bus->pci->subsystem_vendor == 0x1025 && - spec->cdefine.platform_type == 1) { - alc_codec_rename(codec, "ALC271X"); - } else if ((coef & 0xf000) == 0x2000) { - alc_codec_rename(codec, "ALC259"); - } else if ((coef & 0xf000) == 0x3000) { - alc_codec_rename(codec, "ALC258"); - } else if ((coef & 0xfff0) == 0x3010) { - alc_codec_rename(codec, "ALC277"); - } else { - alc_codec_rename(codec, "ALC269VB"); - } - spec->codec_variant = ALC269_TYPE_ALC269VB; - } else if ((coef & 0x00f0) == 0x0020) { - if (coef == 0xa023) - alc_codec_rename(codec, "ALC259"); - else if (coef == 0x6023) - alc_codec_rename(codec, "ALC281X"); - else if (codec->bus->pci->subsystem_vendor == 0x17aa && - codec->bus->pci->subsystem_device == 0x21f3) - alc_codec_rename(codec, "ALC3202"); - else - alc_codec_rename(codec, "ALC269VC"); - spec->codec_variant = ALC269_TYPE_ALC269VC; - } else - alc_fix_pll_init(codec, 0x20, 0x04, 15); - alc269_fill_coef(codec); - } + hda_nid_t srcs[5]; + int num = snd_hda_get_connections(codec, pin, srcs, + ARRAY_SIZE(srcs)); + if (num != 1 || + get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL) + return pin; + return srcs[0]; +} - board_config = alc_board_config(codec, ALC269_MODEL_LAST, - alc269_models, alc269_cfg_tbl); +/* get MIX nid connected to the given pin targeted to DAC */ +static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, + hda_nid_t dac) +{ + hda_nid_t mix[5]; + int i, num; - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; + pin = alc_go_down_to_selector(codec, pin); + num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); + for (i = 0; i < num; i++) { + if (alc_auto_mix_to_dac(codec, mix[i]) == dac) + return mix[i]; } + return 0; +} - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } +/* select the connection from pin to DAC if needed */ +static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, + hda_nid_t dac) +{ + hda_nid_t mix[5]; + int i, num; - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc269_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC269_BASIC; + pin = alc_go_down_to_selector(codec, pin); + num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); + if (num < 2) + return 0; + for (i = 0; i < num; i++) { + if (alc_auto_mix_to_dac(codec, mix[i]) == dac) { + snd_hda_codec_update_cache(codec, pin, 0, + AC_VERB_SET_CONNECT_SEL, i); + return 0; } -#endif } + return 0; +} - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc269_presets[board_config]); +/* look for an empty DAC slot */ +static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t srcs[5]; + int i, j, num; - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + pin = alc_go_down_to_selector(codec, pin); + num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); + for (i = 0; i < num; i++) { + hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); + if (!nid) + continue; + for (j = 0; j < spec->multiout.num_dacs; j++) + if (spec->multiout.dac_nids[j] == nid) + break; + if (j >= spec->multiout.num_dacs) + return nid; } + return 0; +} - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); +/* fill in the dac_nids table from the parsed pin configuration */ +static int alc662_auto_fill_dac_nids(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct alc_spec *spec = codec->spec; + int i; + hda_nid_t dac; - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); + spec->multiout.dac_nids = spec->private_dac_nids; + for (i = 0; i < cfg->line_outs; i++) { + dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]); + if (!dac) + continue; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } - - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - - spec->vmaster_nid = 0x02; - - codec->patch_ops = alc_patch_ops; -#ifdef SND_HDA_NEEDS_RESUME - codec->patch_ops.resume = alc269_resume; -#endif - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - spec->shutup = alc269_shutup; - - alc_init_jacks(codec); -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc269_loopbacks; - if (alc269_mic2_for_mute_led(codec)) - codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps; -#endif - return 0; } -/* - * ALC861 - */ +static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx, + hda_nid_t nid, int idx, unsigned int chs) +{ + return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); +} -static int alc861_parse_auto_config(struct hda_codec *codec) +static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx, + hda_nid_t nid, int idx, unsigned int chs) { - static const hda_nid_t alc861_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 }; - return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids); + return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT)); } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc861_loopbacks[] = { - { 0x15, HDA_INPUT, 0 }, - { 0x15, HDA_INPUT, 1 }, - { 0x15, HDA_INPUT, 2 }, - { 0x15, HDA_INPUT, 3 }, - { } /* end */ -}; -#endif +#define alc662_add_vol_ctl(spec, pfx, nid, chs) \ + __alc662_add_vol_ctl(spec, pfx, nid, 0, chs) +#define alc662_add_sw_ctl(spec, pfx, nid, chs) \ + __alc662_add_sw_ctl(spec, pfx, nid, 0, chs) +#define alc662_add_stereo_vol(spec, pfx, nid) \ + alc662_add_vol_ctl(spec, pfx, nid, 3) +#define alc662_add_stereo_sw(spec, pfx, nid) \ + alc662_add_sw_ctl(spec, pfx, nid, 3) +/* add playback controls from the parsed DAC table */ +static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct alc_spec *spec = codec->spec; + static const char * const chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; + const char *pfx = alc_get_line_out_pfx(spec, true); + hda_nid_t nid, mix, pin; + int i, err, noutputs; -/* Pin config fixes */ -enum { - PINFIX_FSC_AMILO_PI1505, -}; + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; -static const struct alc_fixup alc861_fixups[] = { - [PINFIX_FSC_AMILO_PI1505] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x0b, 0x0221101f }, /* HP */ - { 0x0f, 0x90170310 }, /* speaker */ - { } + for (i = 0; i < noutputs; i++) { + nid = spec->multiout.dac_nids[i]; + if (!nid) + continue; + if (i >= cfg->line_outs) + pin = spec->multi_io[i - 1].pin; + else + pin = cfg->line_out_pins[i]; + mix = alc_auto_dac_to_mix(codec, pin, nid); + if (!mix) + continue; + if (!pfx && i == 2) { + /* Center/LFE */ + err = alc662_add_vol_ctl(spec, "Center", nid, 1); + if (err < 0) + return err; + err = alc662_add_vol_ctl(spec, "LFE", nid, 2); + if (err < 0) + return err; + err = alc662_add_sw_ctl(spec, "Center", mix, 1); + if (err < 0) + return err; + err = alc662_add_sw_ctl(spec, "LFE", mix, 2); + if (err < 0) + return err; + } else { + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __alc662_add_vol_ctl(spec, name, nid, index, 3); + if (err < 0) + return err; + err = __alc662_add_sw_ctl(spec, name, mix, index, 3); + if (err < 0) + return err; } - }, -}; - -static const struct snd_pci_quirk alc861_fixup_tbl[] = { - SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), - {} -}; - -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc861_quirks.c" -#endif + } + return 0; +} -static int patch_alc861(struct hda_codec *codec) +/* add playback controls for speaker and HP outputs */ +/* return DAC nid if any new DAC is assigned */ +static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, + const char *pfx) { - struct alc_spec *spec; - int board_config; + struct alc_spec *spec = codec->spec; + hda_nid_t nid, mix; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + if (!pin) + return 0; + nid = alc_auto_look_for_dac(codec, pin); + if (!nid) { + /* the corresponding DAC is already occupied */ + if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) + return 0; /* no way */ + /* create a switch only */ + return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + } - codec->spec = spec; + mix = alc_auto_dac_to_mix(codec, pin, nid); + if (!mix) + return 0; + err = alc662_add_vol_ctl(spec, pfx, nid, 3); + if (err < 0) + return err; + err = alc662_add_sw_ctl(spec, pfx, mix, 3); + if (err < 0) + return err; + return nid; +} - spec->mixer_nid = 0x15; +/* create playback/capture controls for input pins */ +#define alc662_auto_create_input_ctls \ + alc882_auto_create_input_ctls - board_config = alc_board_config(codec, ALC861_MODEL_LAST, - alc861_models, alc861_cfg_tbl); +static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + hda_nid_t dac) +{ + int i, num; + hda_nid_t srcs[HDA_MAX_CONNECTIONS]; - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; + alc_set_pin_output(codec, nid, pin_type); + num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); + for (i = 0; i < num; i++) { + if (alc_auto_mix_to_dac(codec, srcs[i]) != dac) + continue; + /* need the manual connection? */ + if (num > 1) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, i); + /* unmute mixer widget inputs */ + snd_hda_codec_write(codec, srcs[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + snd_hda_codec_write(codec, srcs[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); + return; } +} - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); +static void alc662_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int pin_type = get_pin_type(spec->autocfg.line_out_type); + int i; + + for (i = 0; i <= HDA_SIDE; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + if (nid) + alc662_auto_set_output_and_unmute(codec, nid, pin_type, + spec->multiout.dac_nids[i]); } +} - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc861_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; +static void alc662_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + + pin = spec->autocfg.hp_pins[0]; + if (pin) + alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, + spec->multiout.hp_nid); + pin = spec->autocfg.speaker_pins[0]; + if (pin) + alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, + spec->multiout.extra_out_nid[0]); +} + +#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID + +static void alc662_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (alc_is_input_pin(codec, nid)) { + alc_set_input_pin(codec, nid, cfg->inputs[i].type); + if (nid != ALC662_PIN_CD_NID && + (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC861_3ST_DIG; + } +} + +#define alc662_auto_init_input_src alc882_auto_init_input_src + +/* + * multi-io helper + */ +static int alc_auto_fill_multi_ios(struct hda_codec *codec, + unsigned int location) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int type, i, num_pins = 0; + + for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + hda_nid_t dac; + unsigned int defcfg, caps; + if (cfg->inputs[i].type != type) + continue; + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) + continue; + if (location && get_defcfg_location(defcfg) != location) + continue; + caps = snd_hda_query_pin_caps(codec, nid); + if (!(caps & AC_PINCAP_OUT)) + continue; + dac = alc_auto_look_for_dac(codec, nid); + if (!dac) + continue; + spec->multi_io[num_pins].pin = nid; + spec->multi_io[num_pins].dac = dac; + num_pins++; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } -#endif - } - - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc861_presets[board_config]); - - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); } + spec->multiout.num_dacs = 1; + if (num_pins < 2) + return 0; + return num_pins; +} - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); +static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x23); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); - } + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = spec->multi_ios + 1; + if (uinfo->value.enumerated.item > spec->multi_ios) + uinfo->value.enumerated.item = spec->multi_ios; + sprintf(uinfo->value.enumerated.name, "%dch", + (uinfo->value.enumerated.item + 1) * 2); + return 0; +} - spec->vmaster_nid = 0x03; +static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2; + return 0; +} - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid = spec->multi_io[idx].pin; - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) { - spec->init_hook = alc_auto_init_std; -#ifdef CONFIG_SND_HDA_POWER_SAVE - spec->power_hook = alc_power_eapd; -#endif + if (!spec->multi_io[idx].ctl_in) + spec->multi_io[idx].ctl_in = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (output) { + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); + alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac); + } else { + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->multi_io[idx].ctl_in); } -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc861_loopbacks; -#endif - return 0; } -/* - * ALC861-VD support - * - * Based on ALC882 - * - * In addition, an independent DAC - */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc861vd_loopbacks alc880_loopbacks -#endif - -static int alc861vd_parse_auto_config(struct hda_codec *codec) +static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids); -} - -enum { - ALC660VD_FIX_ASUS_GPIO1 -}; - -/* reset GPIO1 */ -static const struct alc_fixup alc861vd_fixups[] = { - [ALC660VD_FIX_ASUS_GPIO1] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - { } - } - }, -}; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int i, ch; -static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), - {} -}; + ch = ucontrol->value.enumerated.item[0]; + if (ch < 0 || ch > spec->multi_ios) + return -EINVAL; + if (ch == (spec->ext_channel_count - 1) / 2) + return 0; + spec->ext_channel_count = (ch + 1) * 2; + for (i = 0; i < spec->multi_ios; i++) + alc_set_multi_io(codec, i, i < ch); + spec->multiout.max_channels = spec->ext_channel_count; + return 1; +} -static const struct hda_verb alc660vd_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } +static const struct snd_kcontrol_new alc_auto_channel_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_auto_ch_mode_info, + .get = alc_auto_ch_mode_get, + .put = alc_auto_ch_mode_put, }; -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc861vd_quirks.c" -#endif - -static int patch_alc861vd(struct hda_codec *codec) +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) { - struct alc_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - spec->mixer_nid = 0x0b; - - board_config = alc_board_config(codec, ALC861VD_MODEL_LAST, - alc861vd_models, alc861vd_cfg_tbl); - - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } - - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } - - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc861vd_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC861VD_3ST; - } -#endif - } + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int location, defcfg; + int num_pins; - if (board_config != ALC_MODEL_AUTO) - setup_preset(codec, &alc861vd_presets[board_config]); + if (cfg->line_outs != 1 || + cfg->line_out_type != AUTO_PIN_LINE_OUT) + return 0; - if (codec->vendor_id == 0x10ec0660) { - /* always turn on EAPD */ - add_verb(spec, alc660vd_eapd_verbs); - } + defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); + location = get_defcfg_location(defcfg); - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } + num_pins = alc_auto_fill_multi_ios(codec, location); + if (num_pins > 0) { + struct snd_kcontrol_new *knew; - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + knew = alc_kcontrol_new(spec); + if (!knew) + return -ENOMEM; + *knew = alc_auto_channel_mode_enum; + knew->name = kstrdup("Channel Mode", GFP_KERNEL); + if (!knew->name) + return -ENOMEM; - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x23); - if (err < 0) { - alc_free(codec); - return err; - } - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + spec->multi_ios = num_pins; + spec->ext_channel_count = 2; + spec->multiout.num_dacs = num_pins + 1; } + return 0; +} - spec->vmaster_nid = 0x02; +static int alc662_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc662_ignore[] = { 0x1d, 0 }; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc662_ignore); + if (err < 0) + return err; + if (!spec->autocfg.line_outs) + return 0; /* can't find valid BIOS pin config */ - codec->patch_ops = alc_patch_ops; + err = alc662_auto_fill_dac_nids(codec, &spec->autocfg); + if (err < 0) + return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; + err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + err = alc662_auto_create_extra_out(codec, + spec->autocfg.speaker_pins[0], + "Speaker"); + if (err < 0) + return err; + if (err) + spec->multiout.extra_out_nid[0] = err; + err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], + "Headphone"); + if (err < 0) + return err; + if (err) + spec->multiout.hp_nid = err; + err = alc662_auto_create_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - spec->shutup = alc_eapd_shutup; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc861vd_loopbacks; -#endif + spec->multiout.max_channels = spec->multiout.num_dacs * 2; - return 0; -} + alc_auto_parse_digital(codec); -/* - * ALC662 support - * - * ALC662 is almost identical with ALC880 but has cleaner and more flexible - * configuration. Each pin widget can choose any input DACs and a mixer. - * Each ADC is connected from a mixer of all inputs. This makes possible - * 6-channel independent captures. - * - * In addition, an independent DAC for the multi-playback (not used in this - * driver yet). - */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc662_loopbacks alc880_loopbacks -#endif + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); -/* - * BIOS auto configuration - */ + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; -static int alc662_parse_auto_config(struct hda_codec *codec) -{ - static const hda_nid_t alc662_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 }; - static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - const hda_nid_t *ssids; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) - ssids = alc663_ssids; + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21); else - ssids = alc662_ssids; - return alc_parse_auto_config(codec, alc662_ignore, ssids); + alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); + + return 1; +} + +/* additional initialization for auto-configuration model */ +static void alc662_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc662_auto_init_multi_out(codec); + alc662_auto_init_hp_out(codec); + alc662_auto_init_analog_input(codec); + alc662_auto_init_input_src(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); } static void alc272_fixup_mario(struct hda_codec *codec, @@ -5070,7 +19459,6 @@ enum { ALC272_FIXUP_MARIO, ALC662_FIXUP_CZC_P10T, ALC662_FIXUP_SKU_IGNORE, - ALC662_FIXUP_HP_RP5800, }; static const struct alc_fixup alc662_fixups[] = { @@ -5103,22 +19491,12 @@ static const struct alc_fixup alc662_fixups[] = { .type = ALC_FIXUP_SKU, .v.sku = ALC_FIXUP_SKU_IGNORE, }, - [ALC662_FIXUP_HP_RP5800] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x0221201f }, /* HP out */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), - SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), @@ -5132,12 +19510,6 @@ static const struct alc_model_fixup alc662_fixup_models[] = { }; -/* - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc662_quirks.c" -#endif - static int patch_alc662(struct hda_codec *codec) { struct alc_spec *spec; @@ -5150,8 +19522,6 @@ static int patch_alc662(struct hda_codec *codec) codec->spec = spec; - spec->mixer_nid = 0x0b; - alc_auto_parse_customize_define(codec); alc_fix_pll_init(codec, 0x20, 0x04, 15); @@ -5166,15 +19536,16 @@ static int patch_alc662(struct hda_codec *codec) else if (coef == 0x4011) alc_codec_rename(codec, "ALC656"); - board_config = alc_board_config(codec, ALC662_MODEL_LAST, - alc662_models, alc662_cfg_tbl); + board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, + alc662_models, + alc662_cfg_tbl); if (board_config < 0) { printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", codec->chip_name); - board_config = ALC_MODEL_AUTO; + board_config = ALC662_AUTO; } - if (board_config == ALC_MODEL_AUTO) { + if (board_config == ALC662_AUTO) { alc_pick_fixup(codec, alc662_fixup_models, alc662_fixup_tbl, alc662_fixups); alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); @@ -5183,35 +19554,42 @@ static int patch_alc662(struct hda_codec *codec) if (err < 0) { alc_free(codec); return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { + } else if (!err) { printk(KERN_INFO "hda_codec: Cannot set up configuration " "from BIOS. Using base mode...\n"); board_config = ALC662_3ST_2ch_DIG; } -#endif } - if (board_config != ALC_MODEL_AUTO) + if (has_cdefine_beep(codec)) { + err = snd_hda_attach_beep_device(codec, 0x1); + if (err < 0) { + alc_free(codec); + return err; + } + } + + if (board_config != ALC662_AUTO) setup_preset(codec, &alc662_presets[board_config]); - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + spec->stream_analog_playback = &alc662_pcm_analog_playback; + spec->stream_analog_capture = &alc662_pcm_analog_capture; + + spec->stream_digital_playback = &alc662_pcm_digital_playback; + spec->stream_digital_capture = &alc662_pcm_digital_capture; + + if (!spec->adc_nids) { + spec->adc_nids = alc662_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc662_capsrc_nids; - if (!spec->no_analog && !spec->cap_mixer) + if (!spec->cap_mixer) set_capture_mixer(codec); - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } + if (has_cdefine_beep(codec)) { switch (codec->vendor_id) { case 0x10ec0662: set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); @@ -5231,8 +19609,8 @@ static int patch_alc662(struct hda_codec *codec) alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + if (board_config == ALC662_AUTO) + spec->init_hook = alc662_auto_init; spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); @@ -5274,17 +19652,389 @@ static int patch_alc899(struct hda_codec *codec) /* * ALC680 support */ +#define ALC680_DIGIN_NID ALC880_DIGIN_NID +#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID +#define alc680_modes alc260_modes + +static const hda_nid_t alc680_dac_nids[3] = { + /* Lout1, Lout2, hp */ + 0x02, 0x03, 0x04 +}; + +static const hda_nid_t alc680_adc_nids[3] = { + /* ADC0-2 */ + /* DMIC, MIC, Line-in*/ + 0x07, 0x08, 0x09 +}; + +/* + * Analog capture ADC cgange + */ +static void alc680_rec_autoswitch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int pin_found = 0; + int type_found = AUTO_PIN_LAST; + hda_nid_t nid; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + nid = cfg->inputs[i].pin; + if (!is_jack_detectable(codec, nid)) + continue; + if (snd_hda_jack_detect(codec, nid)) { + if (cfg->inputs[i].type < type_found) { + type_found = cfg->inputs[i].type; + pin_found = nid; + } + } + } + + nid = 0x07; + if (pin_found) + snd_hda_get_connections(codec, pin_found, &nid, 1); + + if (nid != spec->cur_adc) + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); + spec->cur_adc = nid; + snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); +} + +static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + + spec->cur_adc = 0x07; + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + + alc680_rec_autoswitch(codec); + return 0; +} + +static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_cleanup_stream(codec, 0x07); + snd_hda_codec_cleanup_stream(codec, 0x08); + snd_hda_codec_cleanup_stream(codec, 0x09); + return 0; +} + +static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = { + .substreams = 1, /* can be overridden */ + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ + .ops = { + .prepare = alc680_capture_pcm_prepare, + .cleanup = alc680_capture_pcm_cleanup + }, +}; + +static const struct snd_kcontrol_new alc680_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct hda_bind_ctls alc680_bind_cap_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc680_bind_cap_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc680_master_capture_mixer[] = { + HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), + HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), + { } /* end */ +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc680_init_verbs[] = { + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc680_base_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x16; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.num_inputs = 2; + spec->autocfg.inputs[0].pin = 0x18; + spec->autocfg.inputs[0].type = AUTO_PIN_MIC; + spec->autocfg.inputs[1].pin = 0x19; + spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc680_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc_hp_automute(codec); + if ((res >> 26) == ALC880_MIC_EVENT) + alc680_rec_autoswitch(codec); +} + +static void alc680_inithook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc680_rec_autoswitch(codec); +} + +/* create input playback/capture controls for the given pin */ +static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid, + const char *ctlname, int idx) +{ + hda_nid_t dac; + int err; + + switch (nid) { + case 0x14: + dac = 0x02; + break; + case 0x15: + dac = 0x03; + break; + case 0x16: + dac = 0x04; + break; + default: + return 0; + } + if (spec->multiout.dac_nids[0] != dac && + spec->multiout.dac_nids[1] != dac) { + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, + HDA_COMPOSE_AMP_VAL(dac, 3, idx, + HDA_OUTPUT)); + if (err < 0) + return err; + + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, + HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); + + if (err < 0) + return err; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int err; + + spec->multiout.dac_nids = spec->private_dac_nids; + + nid = cfg->line_out_pins[0]; + if (nid) { + const char *name; + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + name = "Speaker"; + else + name = "Front"; + err = alc680_new_analog_output(spec, nid, name, 0); + if (err < 0) + return err; + } + + nid = cfg->speaker_pins[0]; + if (nid) { + err = alc680_new_analog_output(spec, nid, "Speaker", 0); + if (err < 0) + return err; + } + nid = cfg->hp_pins[0]; + if (nid) { + err = alc680_new_analog_output(spec, nid, "Headphone", 0); + if (err < 0) + return err; + } + + return 0; +} + +static void alc680_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type) +{ + alc_set_pin_output(codec, nid, pin_type); +} + +static void alc680_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid = spec->autocfg.line_out_pins[0]; + if (nid) { + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc680_auto_set_output_and_unmute(codec, nid, pin_type); + } +} + +static void alc680_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + pin = spec->autocfg.hp_pins[0]; + if (pin) + alc680_auto_set_output_and_unmute(codec, pin, PIN_HP); + pin = spec->autocfg.speaker_pins[0]; + if (pin) + alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT); +} + +/* pcm configuration: identical with ALC880 */ +#define alc680_pcm_analog_playback alc880_pcm_analog_playback +#define alc680_pcm_analog_capture alc880_pcm_analog_capture +#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture +#define alc680_pcm_digital_playback alc880_pcm_digital_playback +#define alc680_pcm_digital_capture alc880_pcm_digital_capture + +/* + * BIOS auto configuration + */ static int alc680_parse_auto_config(struct hda_codec *codec) { - return alc_parse_auto_config(codec, NULL, NULL); + struct alc_spec *spec = codec->spec; + int err; + static const hda_nid_t alc680_ignore[] = { 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc680_ignore); + if (err < 0) + return err; + + if (!spec->autocfg.line_outs) { + if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } + return 0; /* can't find valid BIOS pin config */ + } + err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = 2; + + dig_only: + /* digital only support output */ + alc_auto_parse_digital(codec); + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc680_init_verbs); + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + return 1; +} + +#define alc680_auto_init_analog_input alc882_auto_init_analog_input + +/* init callback for auto-configuration model -- overriding the default init */ +static void alc680_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc680_auto_init_multi_out(codec); + alc680_auto_init_hp_out(codec); + alc680_auto_init_analog_input(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); } /* + * configuration and preset */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc680_quirks.c" -#endif +static const char * const alc680_models[ALC680_MODEL_LAST] = { + [ALC680_BASE] = "base", + [ALC680_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc680_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), + {} +}; + +static const struct alc_config_preset alc680_presets[] = { + [ALC680_BASE] = { + .mixers = { alc680_base_mixer }, + .cap_mixer = alc680_master_capture_mixer, + .init_verbs = { alc680_init_verbs }, + .num_dacs = ARRAY_SIZE(alc680_dac_nids), + .dac_nids = alc680_dac_nids, + .dig_out_nid = ALC680_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc680_modes), + .channel_mode = alc680_modes, + .unsol_event = alc680_unsol_event, + .setup = alc680_base_setup, + .init_hook = alc680_inithook, + + }, +}; static int patch_alc680(struct hda_codec *codec) { @@ -5298,55 +20048,51 @@ static int patch_alc680(struct hda_codec *codec) codec->spec = spec; - /* ALC680 has no aa-loopback mixer */ + board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST, + alc680_models, + alc680_cfg_tbl); - board_config = alc_board_config(codec, ALC680_MODEL_LAST, - alc680_models, alc680_cfg_tbl); - - if (board_config < 0) { + if (board_config < 0 || board_config >= ALC680_MODEL_LAST) { printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", codec->chip_name); - board_config = ALC_MODEL_AUTO; + board_config = ALC680_AUTO; } - if (board_config == ALC_MODEL_AUTO) { + if (board_config == ALC680_AUTO) { /* automatic parse from the BIOS config */ err = alc680_parse_auto_config(codec); if (err < 0) { alc_free(codec); return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { + } else if (!err) { printk(KERN_INFO "hda_codec: Cannot set up configuration " "from BIOS. Using base mode...\n"); board_config = ALC680_BASE; } -#endif } - if (board_config != ALC_MODEL_AUTO) { + if (board_config != ALC680_AUTO) setup_preset(codec, &alc680_presets[board_config]); -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - spec->stream_analog_capture = &alc680_pcm_analog_auto_capture; -#endif - } - if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); + spec->stream_analog_playback = &alc680_pcm_analog_playback; + spec->stream_analog_capture = &alc680_pcm_analog_auto_capture; + spec->stream_digital_playback = &alc680_pcm_digital_playback; + spec->stream_digital_capture = &alc680_pcm_digital_capture; + + if (!spec->adc_nids) { + spec->adc_nids = alc680_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids); } - if (!spec->no_analog && !spec->cap_mixer) + if (!spec->cap_mixer) set_capture_mixer(codec); spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + if (board_config == ALC680_AUTO) + spec->init_hook = alc680_auto_init; return 0; } diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index 56425a53cf1b..7f81cc2274f3 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -1112,9 +1112,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, @@ -3408,9 +3406,30 @@ static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux, return 0; } -/* look for NID recursively */ -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 1) +static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t nid) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + if (!(get_wcaps(codec, mux) & AC_WCAP_CONN_LIST)) + return -1; + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == nid) + return i; + + for (i = 0; i < nums; i++) { + unsigned int wid_caps = get_wcaps(codec, conn[i]); + unsigned int wid_type = get_wcaps_type(wid_caps); + + if (wid_type != AC_WID_PIN && wid_type != AC_WID_AUD_MIX) + if (get_connection_index(codec, conn[i], nid) >= 0) + return i; + } + return -1; +} /* create a volume assigned to the given pin (only if supported) */ /* return 1 if the volume control is created */ diff --git a/trunk/sound/pci/hda/patch_via.c b/trunk/sound/pci/hda/patch_via.c index f38160b00e16..f43bb0eaed8b 100644 --- a/trunk/sound/pci/hda/patch_via.c +++ b/trunk/sound/pci/hda/patch_via.c @@ -54,10 +54,36 @@ #include "hda_codec.h" #include "hda_local.h" +#define NID_MAPPING (-1) + +/* amp values */ +#define AMP_VAL_IDX_SHIFT 19 +#define AMP_VAL_IDX_MASK (0x0f<<19) + /* Pin Widget NID */ +#define VT1708_HP_NID 0x13 +#define VT1708_DIGOUT_NID 0x14 +#define VT1708_DIGIN_NID 0x16 +#define VT1708_DIGIN_PIN 0x26 #define VT1708_HP_PIN_NID 0x20 #define VT1708_CD_PIN_NID 0x24 +#define VT1709_HP_DAC_NID 0x28 +#define VT1709_DIGOUT_NID 0x13 +#define VT1709_DIGIN_NID 0x17 +#define VT1709_DIGIN_PIN 0x25 + +#define VT1708B_HP_NID 0x25 +#define VT1708B_DIGOUT_NID 0x12 +#define VT1708B_DIGIN_NID 0x15 +#define VT1708B_DIGIN_PIN 0x21 + +#define VT1708S_HP_NID 0x25 +#define VT1708S_DIGOUT_NID 0x12 + +#define VT1702_HP_NID 0x17 +#define VT1702_DIGOUT_NID 0x11 + enum VIA_HDA_CODEC { UNKNOWN = -1, VT1708, @@ -81,39 +107,6 @@ enum VIA_HDA_CODEC { (spec)->codec_type == VT1812 ||\ (spec)->codec_type == VT1802) -#define MAX_NID_PATH_DEPTH 5 - -/* output-path: DAC -> ... -> pin - * idx[] contains the source index number of the next widget; - * e.g. idx[0] is the index of the DAC selected by path[1] widget - * multi[] indicates whether it's a selector widget with multi-connectors - * (i.e. the connection selection is mandatory) - * vol_ctl and mute_ctl contains the NIDs for the assigned mixers - */ -struct nid_path { - int depth; - hda_nid_t path[MAX_NID_PATH_DEPTH]; - unsigned char idx[MAX_NID_PATH_DEPTH]; - unsigned char multi[MAX_NID_PATH_DEPTH]; - unsigned int vol_ctl; - unsigned int mute_ctl; -}; - -/* input-path */ -struct via_input { - hda_nid_t pin; /* input-pin or aa-mix */ - int adc_idx; /* ADC index to be used */ - int mux_idx; /* MUX index (if any) */ - const char *label; /* input-source label */ -}; - -#define VIA_MAX_ADCS 3 - -enum { - STREAM_MULTI_OUT = (1 << 0), - STREAM_INDEP_HP = (1 << 1), -}; - struct via_spec { /* codec parameterization */ const struct snd_kcontrol_new *mixers[6]; @@ -122,66 +115,28 @@ struct via_spec { const struct hda_verb *init_verbs[5]; unsigned int num_iverbs; - char stream_name_analog[32]; - char stream_name_hp[32]; + char *stream_name_analog; const struct hda_pcm_stream *stream_analog_playback; const struct hda_pcm_stream *stream_analog_capture; - char stream_name_digital[32]; + char *stream_name_digital; const struct hda_pcm_stream *stream_digital_playback; const struct hda_pcm_stream *stream_digital_capture; /* playback */ struct hda_multi_out multiout; hda_nid_t slave_dig_outs[2]; - hda_nid_t hp_dac_nid; - hda_nid_t speaker_dac_nid; - int hp_indep_shared; /* indep HP-DAC is shared with side ch */ - int opened_streams; /* STREAM_* bits */ - int active_streams; /* STREAM_* bits */ - int aamix_mode; /* loopback is enabled for output-path? */ - - /* Output-paths: - * There are different output-paths depending on the setup. - * out_path, hp_path and speaker_path are primary paths. If both - * direct DAC and aa-loopback routes are available, these contain - * the former paths. Meanwhile *_mix_path contain the paths with - * loopback mixer. (Since the loopback is only for front channel, - * no out_mix_path for surround channels.) - * The HP output has another path, hp_indep_path, which is used in - * the independent-HP mode. - */ - struct nid_path out_path[HDA_SIDE + 1]; - struct nid_path out_mix_path; - struct nid_path hp_path; - struct nid_path hp_mix_path; - struct nid_path hp_indep_path; - struct nid_path speaker_path; - struct nid_path speaker_mix_path; /* capture */ unsigned int num_adc_nids; - hda_nid_t adc_nids[VIA_MAX_ADCS]; - hda_nid_t mux_nids[VIA_MAX_ADCS]; - hda_nid_t aa_mix_nid; + const hda_nid_t *adc_nids; + hda_nid_t mux_nids[3]; hda_nid_t dig_in_nid; + hda_nid_t dig_in_pin; /* capture source */ - bool dyn_adc_switch; - int num_inputs; - struct via_input inputs[AUTO_CFG_MAX_INS + 1]; - unsigned int cur_mux[VIA_MAX_ADCS]; - - /* dynamic DAC switching */ - unsigned int cur_dac_stream_tag; - unsigned int cur_dac_format; - unsigned int cur_hp_stream_tag; - unsigned int cur_hp_format; - - /* dynamic ADC switching */ - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; + const struct hda_input_mux *input_mux; + unsigned int cur_mux[3]; /* PCM information */ struct hda_pcm pcm_rec[3]; @@ -189,38 +144,28 @@ struct via_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct snd_array kctls; + struct hda_input_mux private_imux[2]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; /* HP mode source */ + const struct hda_input_mux *hp_mux; unsigned int hp_independent_mode; + unsigned int hp_independent_mode_index; + unsigned int smart51_enabled; unsigned int dmic_enabled; - unsigned int no_pin_power_ctl; enum VIA_HDA_CODEC codec_type; - /* smart51 setup */ - unsigned int smart51_nums; - hda_nid_t smart51_pins[2]; - int smart51_idxs[2]; - const char *smart51_labels[2]; - unsigned int smart51_enabled; - /* work to check hp jack state */ struct hda_codec *codec; struct delayed_work vt1708_hp_work; - int vt1708_jack_detect; + int vt1708_jack_detectect; int vt1708_hp_present; void (*set_widgets_power_state)(struct hda_codec *codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; - int num_loopbacks; - struct hda_amp_list loopback_list[8]; - - /* bind capture-volume */ - struct hda_bind_ctls *bind_cap_vol; - struct hda_bind_ctls *bind_cap_sw; - - struct mutex config_mutex; +#endif }; static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec); @@ -232,7 +177,6 @@ static struct via_spec * via_new_spec(struct hda_codec *codec) if (spec == NULL) return NULL; - mutex_init(&spec->config_mutex); codec->spec = spec; spec->codec = codec; spec->codec_type = get_codec_type(codec); @@ -293,23 +237,33 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) #define VIA_JACK_EVENT 0x20 #define VIA_HP_EVENT 0x01 #define VIA_GPIO_EVENT 0x02 -#define VIA_LINE_EVENT 0x03 +#define VIA_MONO_EVENT 0x03 +#define VIA_SPEAKER_EVENT 0x04 +#define VIA_BIND_HP_EVENT 0x05 enum { VIA_CTL_WIDGET_VOL, VIA_CTL_WIDGET_MUTE, VIA_CTL_WIDGET_ANALOG_MUTE, + VIA_CTL_WIDGET_BIND_PIN_MUTE, }; -static void analog_low_current_mode(struct hda_codec *codec); -static bool is_aa_path_mute(struct hda_codec *codec); +enum { + AUTO_SEQ_FRONT = 0, + AUTO_SEQ_SURROUND, + AUTO_SEQ_CENLFE, + AUTO_SEQ_SIDE +}; + +static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); +static int is_aa_path_mute(struct hda_codec *codec); static void vt1708_start_hp_work(struct via_spec *spec) { if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) return; snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, - !spec->vt1708_jack_detect); + !spec->vt1708_jack_detectect); if (!delayed_work_pending(&spec->vt1708_hp_work)) schedule_delayed_work(&spec->vt1708_hp_work, msecs_to_jiffies(100)); @@ -323,7 +277,7 @@ static void vt1708_stop_hp_work(struct via_spec *spec) && !is_aa_path_mute(spec->codec)) return; snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, - !spec->vt1708_jack_detect); + !spec->vt1708_jack_detectect); cancel_delayed_work_sync(&spec->vt1708_hp_work); } @@ -341,7 +295,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); set_widgets_power_state(codec); - analog_low_current_mode(snd_kcontrol_chip(kcontrol)); + analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { if (is_aa_path_mute(codec)) vt1708_start_hp_work(codec->spec); @@ -361,44 +315,168 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, .put = analog_input_switch_put, \ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } +static void via_hp_bind_automute(struct hda_codec *codec); + +static int bind_pin_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + int i; + int change = 0; + + long *valp = ucontrol->value.integer.value; + int lmute, rmute; + if (strstr(kcontrol->id.name, "Switch") == NULL) { + snd_printd("Invalid control!\n"); + return change; + } + change = snd_hda_mixer_amp_switch_put(kcontrol, + ucontrol); + /* Get mute value */ + lmute = *valp ? 0 : HDA_AMP_MUTE; + valp++; + rmute = *valp ? 0 : HDA_AMP_MUTE; + + /* Set hp pins */ + if (!spec->hp_independent_mode) { + for (i = 0; i < spec->autocfg.hp_outs; i++) { + snd_hda_codec_amp_update( + codec, spec->autocfg.hp_pins[i], + 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, + lmute); + snd_hda_codec_amp_update( + codec, spec->autocfg.hp_pins[i], + 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, + rmute); + } + } + + if (!lmute && !rmute) { + /* Line Outs */ + for (i = 0; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.line_out_pins[i], + HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); + /* Speakers */ + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.speaker_pins[i], + HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); + /* unmute */ + via_hp_bind_automute(codec); + + } else { + if (lmute) { + /* Mute all left channels */ + for (i = 1; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.line_out_pins[i], + 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, + lmute); + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.speaker_pins[i], + 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, + lmute); + } + if (rmute) { + /* mute all right channels */ + for (i = 1; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.line_out_pins[i], + 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, + rmute); + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.speaker_pins[i], + 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, + rmute); + } + } + return change; +} + +#define BIND_PIN_MUTE \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = NULL, \ + .index = 0, \ + .info = snd_hda_mixer_amp_switch_info, \ + .get = snd_hda_mixer_amp_switch_get, \ + .put = bind_pin_switch_put, \ + .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } + static const struct snd_kcontrol_new via_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), ANALOG_INPUT_MUTE, + BIND_PIN_MUTE, }; +static const hda_nid_t vt1708_adc_nids[2] = { + /* ADC1-2 */ + 0x15, 0x27 +}; -/* add dynamic controls */ -static struct snd_kcontrol_new *__via_clone_ctl(struct via_spec *spec, - const struct snd_kcontrol_new *tmpl, - const char *name) -{ - struct snd_kcontrol_new *knew; +static const hda_nid_t vt1709_adc_nids[3] = { + /* ADC1-2 */ + 0x14, 0x15, 0x16 +}; + +static const hda_nid_t vt1708B_adc_nids[2] = { + /* ADC1-2 */ + 0x13, 0x14 +}; + +static const hda_nid_t vt1708S_adc_nids[2] = { + /* ADC1-2 */ + 0x13, 0x14 +}; + +static const hda_nid_t vt1702_adc_nids[3] = { + /* ADC1-2 */ + 0x12, 0x20, 0x1F +}; + +static const hda_nid_t vt1718S_adc_nids[2] = { + /* ADC1-2 */ + 0x10, 0x11 +}; + +static const hda_nid_t vt1716S_adc_nids[2] = { + /* ADC1-2 */ + 0x13, 0x14 +}; + +static const hda_nid_t vt2002P_adc_nids[2] = { + /* ADC1-2 */ + 0x10, 0x11 +}; + +static const hda_nid_t vt1812_adc_nids[2] = { + /* ADC1-2 */ + 0x10, 0x11 +}; - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return NULL; - *knew = *tmpl; - if (!name) - name = tmpl->name; - if (name) { - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) - return NULL; - } - return knew; -} +/* add dynamic controls */ static int __via_add_control(struct via_spec *spec, int type, const char *name, int idx, unsigned long val) { struct snd_kcontrol_new *knew; - knew = __via_clone_ctl(spec, &via_control_templates[type], name); + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); if (!knew) return -ENOMEM; - knew->index = idx; + *knew = via_control_templates[type]; + knew->name = kstrdup(name, GFP_KERNEL); + if (!knew->name) + return -ENOMEM; if (get_amp_nid_(val)) knew->subdevice = HDA_SUBDEV_AMP_FLAG; knew->private_value = val; @@ -408,7 +486,21 @@ static int __via_add_control(struct via_spec *spec, int type, const char *name, #define via_add_control(spec, type, name, val) \ __via_add_control(spec, type, name, 0, val) -#define via_clone_control(spec, tmpl) __via_clone_ctl(spec, tmpl, NULL) +static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, + const struct snd_kcontrol_new *tmpl) +{ + struct snd_kcontrol_new *knew; + + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); + if (!knew) + return NULL; + *knew = *tmpl; + knew->name = kstrdup(tmpl->name, GFP_KERNEL); + if (!knew->name) + return NULL; + return knew; +} static void via_free_kctls(struct hda_codec *codec) { @@ -443,208 +535,58 @@ static int via_new_analog_input(struct via_spec *spec, const char *ctlname, return 0; } -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 0) - -static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, - unsigned int mask) -{ - unsigned int caps; - if (!nid) - return false; - caps = get_wcaps(codec, nid); - if (dir == HDA_INPUT) - caps &= AC_WCAP_IN_AMP; - else - caps &= AC_WCAP_OUT_AMP; - if (!caps) - return false; - if (query_amp_caps(codec, nid, dir) & mask) - return true; - return false; -} - -#define have_mute(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) - -/* enable/disable the output-route mixers */ -static void activate_output_mix(struct hda_codec *codec, struct nid_path *path, - hda_nid_t mix_nid, int idx, bool enable) -{ - int i, num, val; - - if (!path) - return; - num = snd_hda_get_conn_list(codec, mix_nid, NULL); - for (i = 0; i < num; i++) { - if (i == idx) - val = AMP_IN_UNMUTE(i); - else - val = AMP_IN_MUTE(i); - snd_hda_codec_write(codec, mix_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); - } -} - -/* enable/disable the output-route */ -static void activate_output_path(struct hda_codec *codec, struct nid_path *path, - bool enable, bool force) -{ - struct via_spec *spec = codec->spec; - int i; - for (i = 0; i < path->depth; i++) { - hda_nid_t src, dst; - int idx = path->idx[i]; - src = path->path[i]; - if (i < path->depth - 1) - dst = path->path[i + 1]; - else - dst = 0; - if (enable && path->multi[i]) - snd_hda_codec_write(codec, dst, 0, - AC_VERB_SET_CONNECT_SEL, idx); - if (!force && (dst == spec->aa_mix_nid)) - continue; - if (have_mute(codec, dst, HDA_INPUT)) - activate_output_mix(codec, path, dst, idx, enable); - if (!force && (src == path->vol_ctl || src == path->mute_ctl)) - continue; - if (have_mute(codec, src, HDA_OUTPUT)) { - int val = enable ? AMP_OUT_UNMUTE : AMP_OUT_MUTE; - snd_hda_codec_write(codec, src, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); - } - } -} - -/* set the given pin as output */ -static void init_output_pin(struct hda_codec *codec, hda_nid_t pin, - int pin_type) +static void via_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + int dac_idx) { - if (!pin) - return; - snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + /* set as output */ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); - if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD) - snd_hda_codec_write(codec, pin, 0, + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x02); } -static void via_auto_init_output(struct hda_codec *codec, - struct nid_path *path, int pin_type) -{ - unsigned int caps; - hda_nid_t pin; - - if (!path->depth) - return; - pin = path->path[path->depth - 1]; - - init_output_pin(codec, pin, pin_type); - caps = query_amp_caps(codec, pin, HDA_OUTPUT); - if (caps & AC_AMPCAP_MUTE) { - unsigned int val; - val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; - snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE | val); - } - activate_output_path(codec, path, true, true); /* force on */ -} static void via_auto_init_multi_out(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - struct nid_path *path; int i; - for (i = 0; i < spec->autocfg.line_outs + spec->smart51_nums; i++) { - path = &spec->out_path[i]; - if (!i && spec->aamix_mode && spec->out_mix_path.depth) - path = &spec->out_mix_path; - via_auto_init_output(codec, path, PIN_OUT); - } -} - -/* deactivate the inactive headphone-paths */ -static void deactivate_hp_paths(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int shared = spec->hp_indep_shared; - - if (spec->hp_independent_mode) { - activate_output_path(codec, &spec->hp_path, false, false); - activate_output_path(codec, &spec->hp_mix_path, false, false); - if (shared) - activate_output_path(codec, &spec->out_path[shared], - false, false); - } else if (spec->aamix_mode || !spec->hp_path.depth) { - activate_output_path(codec, &spec->hp_indep_path, false, false); - activate_output_path(codec, &spec->hp_path, false, false); - } else { - activate_output_path(codec, &spec->hp_indep_path, false, false); - activate_output_path(codec, &spec->hp_mix_path, false, false); + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + if (nid) + via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); } } static void via_auto_init_hp_out(struct hda_codec *codec) { struct via_spec *spec = codec->spec; + hda_nid_t pin; + int i; - if (!spec->hp_path.depth) { - via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP); - return; - } - deactivate_hp_paths(codec); - if (spec->hp_independent_mode) - via_auto_init_output(codec, &spec->hp_indep_path, PIN_HP); - else if (spec->aamix_mode) - via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP); - else - via_auto_init_output(codec, &spec->hp_path, PIN_HP); -} - -static void via_auto_init_speaker_out(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (!spec->autocfg.speaker_outs) - return; - if (!spec->speaker_path.depth) { - via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT); - return; - } - if (!spec->aamix_mode) { - activate_output_path(codec, &spec->speaker_mix_path, - false, false); - via_auto_init_output(codec, &spec->speaker_path, PIN_OUT); - } else { - activate_output_path(codec, &spec->speaker_path, false, false); - via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT); + for (i = 0; i < spec->autocfg.hp_outs; i++) { + pin = spec->autocfg.hp_pins[i]; + if (pin) /* connect to front */ + via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); } } -static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin); -static void via_hp_automute(struct hda_codec *codec); +static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin); static void via_auto_init_analog_input(struct hda_codec *codec) { struct via_spec *spec = codec->spec; const struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t conn[HDA_MAX_CONNECTIONS]; unsigned int ctl; - int i, num_conns; - - /* init ADCs */ - for (i = 0; i < spec->num_adc_nids; i++) { - snd_hda_codec_write(codec, spec->adc_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } + int i; - /* init pins */ for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; - if (spec->smart51_enabled && is_smart51_pins(codec, nid)) + if (spec->smart51_enabled && is_smart51_pins(spec, nid)) ctl = PIN_OUT; else if (cfg->inputs[i].type == AUTO_PIN_MIC) ctl = PIN_VREF50; @@ -653,32 +595,6 @@ static void via_auto_init_analog_input(struct hda_codec *codec) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ctl); } - - /* init input-src */ - for (i = 0; i < spec->num_adc_nids; i++) { - int adc_idx = spec->inputs[spec->cur_mux[i]].adc_idx; - if (spec->mux_nids[adc_idx]) { - int mux_idx = spec->inputs[spec->cur_mux[i]].mux_idx; - snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0, - AC_VERB_SET_CONNECT_SEL, - mux_idx); - } - if (spec->dyn_adc_switch) - break; /* only one input-src */ - } - - /* init aa-mixer */ - if (!spec->aa_mix_nid) - return; - num_conns = snd_hda_get_connections(codec, spec->aa_mix_nid, conn, - ARRAY_SIZE(conn)); - for (i = 0; i < num_conns; i++) { - unsigned int caps = get_wcaps(codec, conn[i]); - if (get_wcaps_type(caps) == AC_WID_PIN) - snd_hda_codec_write(codec, spec->aa_mix_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(i)); - } } static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, @@ -689,13 +605,9 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, unsigned no_presence = (def_conf & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */ + unsigned present = snd_hda_jack_detect(codec, nid); struct via_spec *spec = codec->spec; - unsigned present = 0; - - no_presence |= spec->no_pin_power_ctl; - if (!no_presence) - present = snd_hda_jack_detect(codec, nid); - if ((spec->smart51_enabled && is_smart51_pins(codec, nid)) + if ((spec->smart51_enabled && is_smart51_pins(spec, nid)) || ((no_presence || present) && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) { *affected_parm = AC_PWRST_D0; /* if it's connected */ @@ -706,139 +618,124 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); } -static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +/* + * input MUX handling + */ +static int via_mux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - static const char * const texts[] = { - "Disabled", "Enabled" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + return snd_hda_input_mux_info(spec->input_mux, uinfo); } -static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int via_mux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = !spec->no_pin_power_ctl; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; return 0; } -static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int via_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - unsigned int val = !ucontrol->value.enumerated.item[0]; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + int ret; - if (val == spec->no_pin_power_ctl) - return 0; - spec->no_pin_power_ctl = val; - set_widgets_power_state(codec); - return 1; -} + if (!spec->mux_nids[adc_idx]) + return -EINVAL; + /* switch to D0 beofre change index */ + if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0, + AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0) + snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); -static const struct snd_kcontrol_new via_pin_power_ctl_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Dynamic Power-Control", - .info = via_pin_power_ctl_info, - .get = via_pin_power_ctl_get, - .put = via_pin_power_ctl_put, -}; + ret = snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + spec->mux_nids[adc_idx], + &spec->cur_mux[adc_idx]); + /* update jack power state */ + set_widgets_power_state(codec); + return ret; +} static int via_independent_hp_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char * const texts[] = { "OFF", "ON" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + return snd_hda_input_mux_info(spec->hp_mux, uinfo); } static int via_independent_hp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; + hda_nid_t nid = kcontrol->private_value; + unsigned int pinsel; + + /* use !! to translate conn sel 2 for VT1718S */ + pinsel = !!snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONNECT_SEL, + 0x00); + ucontrol->value.enumerated.item[0] = pinsel; - ucontrol->value.enumerated.item[0] = spec->hp_independent_mode; return 0; } -/* adjust spec->multiout setup according to the current flags */ -static void setup_playback_multi_pcm(struct via_spec *spec) +static void activate_ctl(struct hda_codec *codec, const char *name, int active) { - const struct auto_pin_cfg *cfg = &spec->autocfg; - spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums; - spec->multiout.hp_nid = 0; - if (!spec->hp_independent_mode) { - if (!spec->hp_indep_shared) - spec->multiout.hp_nid = spec->hp_dac_nid; - } else { - if (spec->hp_indep_shared) - spec->multiout.num_dacs = cfg->line_outs - 1; + struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name); + if (ctl) { + ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + ctl->vd[0].access |= active + ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(codec->bus->card, + SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id); } } -/* update DAC setups according to indep-HP switch; - * this function is called only when indep-HP is modified - */ -static void switch_indep_hp_dacs(struct hda_codec *codec) +static hda_nid_t side_mute_channel(struct via_spec *spec) { - struct via_spec *spec = codec->spec; - int shared = spec->hp_indep_shared; - hda_nid_t shared_dac, hp_dac; + switch (spec->codec_type) { + case VT1708: return 0x1b; + case VT1709_10CH: return 0x29; + case VT1708B_8CH: /* fall thru */ + case VT1708S: return 0x27; + case VT2002P: return 0x19; + case VT1802: return 0x15; + case VT1812: return 0x15; + default: return 0; + } +} - if (!spec->opened_streams) - return; +static int update_side_mute_status(struct hda_codec *codec) +{ + /* mute side channel */ + struct via_spec *spec = codec->spec; + unsigned int parm; + hda_nid_t sw3 = side_mute_channel(spec); - shared_dac = shared ? spec->multiout.dac_nids[shared] : 0; - hp_dac = spec->hp_dac_nid; - if (spec->hp_independent_mode) { - /* switch to indep-HP mode */ - if (spec->active_streams & STREAM_MULTI_OUT) { - __snd_hda_codec_cleanup_stream(codec, hp_dac, 1); - __snd_hda_codec_cleanup_stream(codec, shared_dac, 1); - } - if (spec->active_streams & STREAM_INDEP_HP) - snd_hda_codec_setup_stream(codec, hp_dac, - spec->cur_hp_stream_tag, 0, - spec->cur_hp_format); - } else { - /* back to HP or shared-DAC */ - if (spec->active_streams & STREAM_INDEP_HP) - __snd_hda_codec_cleanup_stream(codec, hp_dac, 1); - if (spec->active_streams & STREAM_MULTI_OUT) { - hda_nid_t dac; - int ch; - if (shared_dac) { /* reset mutli-ch DAC */ - dac = shared_dac; - ch = shared * 2; - } else { /* reset HP DAC */ - dac = hp_dac; - ch = 0; - } - snd_hda_codec_setup_stream(codec, dac, - spec->cur_dac_stream_tag, ch, - spec->cur_dac_format); - } + if (sw3) { + if (VT2002P_COMPATIBLE(spec)) + parm = spec->hp_independent_mode ? + AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1); + else + parm = spec->hp_independent_mode ? + AMP_OUT_MUTE : AMP_OUT_UNMUTE; + snd_hda_codec_write(codec, sw3, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); + if (spec->codec_type == VT1812) + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); } - setup_playback_multi_pcm(spec); + return 0; } static int via_independent_hp_put(struct snd_kcontrol *kcontrol, @@ -846,46 +743,66 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - int cur, shared; - - mutex_lock(&spec->config_mutex); - cur = !!ucontrol->value.enumerated.item[0]; - if (spec->hp_independent_mode == cur) { - mutex_unlock(&spec->config_mutex); - return 0; - } - spec->hp_independent_mode = cur; - shared = spec->hp_indep_shared; - deactivate_hp_paths(codec); - if (cur) - activate_output_path(codec, &spec->hp_indep_path, true, false); - else { - if (shared) - activate_output_path(codec, &spec->out_path[shared], - true, false); - if (spec->aamix_mode || !spec->hp_path.depth) - activate_output_path(codec, &spec->hp_mix_path, - true, false); - else - activate_output_path(codec, &spec->hp_path, - true, false); + hda_nid_t nid = kcontrol->private_value; + unsigned int pinsel = ucontrol->value.enumerated.item[0]; + unsigned int parm0, parm1; + /* Get Independent Mode index of headphone pin widget */ + spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel + ? 1 : 0; + if (spec->codec_type == VT1718S) { + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, pinsel ? 2 : 0); + /* Set correct mute switch for MW3 */ + parm0 = spec->hp_independent_mode ? + AMP_IN_UNMUTE(0) : AMP_IN_MUTE(0); + parm1 = spec->hp_independent_mode ? + AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1); + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm0); + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm1); } + else + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, pinsel); - switch_indep_hp_dacs(codec); - mutex_unlock(&spec->config_mutex); - + if (spec->codec_type == VT1812) + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_CONNECT_SEL, pinsel); + if (spec->multiout.hp_nid && spec->multiout.hp_nid + != spec->multiout.dac_nids[HDA_FRONT]) + snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid, + 0, 0, 0); + + update_side_mute_status(codec); + /* update HP volume/swtich active state */ + if (spec->codec_type == VT1708S + || spec->codec_type == VT1702 + || spec->codec_type == VT1718S + || spec->codec_type == VT1716S + || VT2002P_COMPATIBLE(spec)) { + activate_ctl(codec, "Headphone Playback Volume", + spec->hp_independent_mode); + activate_ctl(codec, "Headphone Playback Switch", + spec->hp_independent_mode); + } /* update jack power state */ set_widgets_power_state(codec); - via_hp_automute(codec); - return 1; + return 0; } -static const struct snd_kcontrol_new via_hp_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Independent HP", - .info = via_independent_hp_info, - .get = via_independent_hp_get, - .put = via_independent_hp_put, +static const struct snd_kcontrol_new via_hp_mixer[2] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Independent HP", + .info = via_independent_hp_info, + .get = via_independent_hp_get, + .put = via_independent_hp_put, + }, + { + .iface = NID_MAPPING, + .name = "Independent HP", + }, }; static int via_hp_build(struct hda_codec *codec) @@ -893,28 +810,61 @@ static int via_hp_build(struct hda_codec *codec) struct via_spec *spec = codec->spec; struct snd_kcontrol_new *knew; hda_nid_t nid; + int nums; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; + + switch (spec->codec_type) { + case VT1718S: + nid = 0x34; + break; + case VT2002P: + case VT1802: + nid = 0x35; + break; + case VT1812: + nid = 0x3d; + break; + default: + nid = spec->autocfg.hp_pins[0]; + break; + } + + if (spec->codec_type != VT1708) { + nums = snd_hda_get_connections(codec, nid, + conn, HDA_MAX_CONNECTIONS); + if (nums <= 1) + return 0; + } - nid = spec->autocfg.hp_pins[0]; - knew = via_clone_control(spec, &via_hp_mixer); + knew = via_clone_control(spec, &via_hp_mixer[0]); if (knew == NULL) return -ENOMEM; knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; + knew->private_value = nid; + + nid = side_mute_channel(spec); + if (nid) { + knew = via_clone_control(spec, &via_hp_mixer[1]); + if (knew == NULL) + return -ENOMEM; + knew->subdevice = nid; + } + + return 0; +} - return 0; -} - static void notify_aa_path_ctls(struct hda_codec *codec) { - struct via_spec *spec = codec->spec; int i; - - for (i = 0; i < spec->smart51_nums; i++) { - struct snd_kcontrol *ctl; - struct snd_ctl_elem_id id; - memset(&id, 0, sizeof(id)); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - sprintf(id.name, "%s Playback Volume", spec->smart51_labels[i]); + struct snd_ctl_elem_id id; + const char *labels[] = {"Mic", "Front Mic", "Line", "Rear Mic"}; + struct snd_kcontrol *ctl; + + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + for (i = 0; i < ARRAY_SIZE(labels); i++) { + sprintf(id.name, "%s Playback Volume", labels[i]); ctl = snd_hda_find_mixer_ctl(codec, id.name); if (ctl) snd_ctl_notify(codec->bus->card, @@ -926,28 +876,66 @@ static void notify_aa_path_ctls(struct hda_codec *codec) static void mute_aa_path(struct hda_codec *codec, int mute) { struct via_spec *spec = codec->spec; - int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE; + hda_nid_t nid_mixer; + int start_idx; + int end_idx; int i; - + /* get nid of MW0 and start & end index */ + switch (spec->codec_type) { + case VT1708: + nid_mixer = 0x17; + start_idx = 2; + end_idx = 4; + break; + case VT1709_10CH: + case VT1709_6CH: + nid_mixer = 0x18; + start_idx = 2; + end_idx = 4; + break; + case VT1708B_8CH: + case VT1708B_4CH: + case VT1708S: + case VT1716S: + nid_mixer = 0x16; + start_idx = 2; + end_idx = 4; + break; + case VT1718S: + nid_mixer = 0x21; + start_idx = 1; + end_idx = 3; + break; + default: + return; + } /* check AA path's mute status */ - for (i = 0; i < spec->smart51_nums; i++) { - if (spec->smart51_idxs[i] < 0) - continue; - snd_hda_codec_amp_stereo(codec, spec->aa_mix_nid, - HDA_INPUT, spec->smart51_idxs[i], + for (i = start_idx; i <= end_idx; i++) { + int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE; + snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i, HDA_AMP_MUTE, val); } } - -static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin) +static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin) { - struct via_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; int i; - for (i = 0; i < spec->smart51_nums; i++) - if (spec->smart51_pins[i] == pin) - return true; - return false; + for (i = 0; i < cfg->num_inputs; i++) { + if (pin == cfg->inputs[i].pin) + return cfg->inputs[i].type <= AUTO_PIN_LINE_IN; + } + return 0; +} + +static int via_smart51_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 via_smart51_get(struct snd_kcontrol *kcontrol, @@ -955,8 +943,23 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; + int on = 1; + int i; - *ucontrol->value.integer.value = spec->smart51_enabled; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + int ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) + continue; + if (cfg->inputs[i].type == AUTO_PIN_MIC && + spec->hp_independent_mode && spec->codec_type != VT1718S) + continue; /* ignore FMic for independent HP */ + if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN)) + on = 0; + } + *ucontrol->value.integer.value = on; return 0; } @@ -965,14 +968,21 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; int out_in = *ucontrol->value.integer.value ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN; int i; - for (i = 0; i < spec->smart51_nums; i++) { - hda_nid_t nid = spec->smart51_pins[i]; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; unsigned int parm; + if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) + continue; + if (cfg->inputs[i].type == AUTO_PIN_MIC && + spec->hp_independent_mode && spec->codec_type != VT1718S) + continue; /* don't retask FMic for independent HP */ + parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); @@ -984,59 +994,171 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, mute_aa_path(codec, 1); notify_aa_path_ctls(codec); } + if (spec->codec_type == VT1718S) { + snd_hda_codec_amp_stereo( + codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE, + HDA_AMP_UNMUTE); + } + if (cfg->inputs[i].type == AUTO_PIN_MIC) { + if (spec->codec_type == VT1708S + || spec->codec_type == VT1716S) { + /* input = index 1 (AOW3) */ + snd_hda_codec_write( + codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, 1); + snd_hda_codec_amp_stereo( + codec, nid, HDA_OUTPUT, + 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE); + } + } } spec->smart51_enabled = *ucontrol->value.integer.value; set_widgets_power_state(codec); return 1; } -static const struct snd_kcontrol_new via_smart51_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Smart 5.1", - .count = 1, - .info = snd_ctl_boolean_mono_info, - .get = via_smart51_get, - .put = via_smart51_put, +static const struct snd_kcontrol_new via_smart51_mixer[2] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Smart 5.1", + .count = 1, + .info = via_smart51_info, + .get = via_smart51_get, + .put = via_smart51_put, + }, + { + .iface = NID_MAPPING, + .name = "Smart 5.1", + } }; -static int via_smart51_build(struct hda_codec *codec) +static int via_smart51_build(struct via_spec *spec) { - struct via_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; + const struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; + int i; - if (!spec->smart51_nums) + if (!cfg) + return 0; + if (cfg->line_outs > 2) return 0; - if (!via_clone_control(spec, &via_smart51_mixer)) + + knew = via_clone_control(spec, &via_smart51_mixer[0]); + if (knew == NULL) return -ENOMEM; + + for (i = 0; i < cfg->num_inputs; i++) { + nid = cfg->inputs[i].pin; + if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) { + knew = via_clone_control(spec, &via_smart51_mixer[1]); + if (knew == NULL) + return -ENOMEM; + knew->subdevice = nid; + break; + } + } + return 0; } -/* check AA path's mute status */ -static bool is_aa_path_mute(struct hda_codec *codec) +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1708_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +/* check AA path's mute statue */ +static int is_aa_path_mute(struct hda_codec *codec) { + int mute = 1; + hda_nid_t nid_mixer; + int start_idx; + int end_idx; + int i; struct via_spec *spec = codec->spec; - const struct hda_amp_list *p; - int i, ch, v; - - for (i = 0; i < spec->num_loopbacks; i++) { - p = &spec->loopback_list[i]; - for (ch = 0; ch < 2; ch++) { - v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, - p->idx); - if (!(v & HDA_AMP_MUTE) && v > 0) - return false; + /* get nid of MW0 and start & end index */ + switch (spec->codec_type) { + case VT1708B_8CH: + case VT1708B_4CH: + case VT1708S: + case VT1716S: + nid_mixer = 0x16; + start_idx = 2; + end_idx = 4; + break; + case VT1702: + nid_mixer = 0x1a; + start_idx = 1; + end_idx = 3; + break; + case VT1718S: + nid_mixer = 0x21; + start_idx = 1; + end_idx = 3; + break; + case VT2002P: + case VT1812: + case VT1802: + nid_mixer = 0x21; + start_idx = 0; + end_idx = 2; + break; + default: + return 0; + } + /* check AA path's mute status */ + for (i = start_idx; i <= end_idx; i++) { + unsigned int con_list = snd_hda_codec_read( + codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4); + int shift = 8 * (i % 4); + hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift; + unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin); + if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) { + /* check mute status while the pin is connected */ + int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0, + HDA_INPUT, i) >> 7; + int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1, + HDA_INPUT, i) >> 7; + if (!mute_l || !mute_r) { + mute = 0; + break; + } } } - return true; + return mute; } /* enter/exit analog low-current mode */ -static void analog_low_current_mode(struct hda_codec *codec) +static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) { struct via_spec *spec = codec->spec; - bool enable; - unsigned int verb, parm; + static int saved_stream_idle = 1; /* saved stream idle status */ + int enable = is_aa_path_mute(codec); + unsigned int verb = 0; + unsigned int parm = 0; - enable = is_aa_path_mute(codec) && (spec->opened_streams != 0); + if (stream_idle == -1) /* stream status did not change */ + enable = enable && saved_stream_idle; + else { + enable = enable && stream_idle; + saved_stream_idle = stream_idle; + } /* decide low current mode's verb & parameter */ switch (spec->codec_type) { @@ -1071,69 +1193,119 @@ static void analog_low_current_mode(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static const struct hda_verb vt1708_init_verbs[] = { +static const struct hda_verb vt1708_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output mixers (0x19 - 0x1b) + */ + /* set vol=0 to output mixers */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Setup default input MW0 to PW4 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0}, + /* PW9 Output enable */ + {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* power down jack detect function */ {0x1, 0xf81, 0x1}, { } }; -static void set_stream_open(struct hda_codec *codec, int bit, bool active) -{ - struct via_spec *spec = codec->spec; - - if (active) - spec->opened_streams |= bit; - else - spec->opened_streams &= ~bit; - analog_low_current_mode(codec); -} - -static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, +static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int err; - - spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums; - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - set_stream_open(codec, STREAM_MULTI_OUT, true); - err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); - if (err < 0) { - set_stream_open(codec, STREAM_MULTI_OUT, false); - return err; - } - return 0; -} - -static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_open(codec, STREAM_MULTI_OUT, false); - return 0; + int idle = substream->pstr->substream_opened == 1 + && substream->ref_count == 0; + analog_low_current_mode(codec, idle); + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + hinfo); } -static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +static void playback_multi_pcm_prep_0(struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; + struct hda_multi_out *mout = &spec->multiout; + const hda_nid_t *nids = mout->dac_nids; + int chs = substream->runtime->channels; + int i; - if (snd_BUG_ON(!spec->hp_dac_nid)) - return -EINVAL; - set_stream_open(codec, STREAM_INDEP_HP, true); - return 0; -} - -static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_open(codec, STREAM_INDEP_HP, false); - return 0; + mutex_lock(&codec->spdif_mutex); + if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { + if (chs == 2 && + snd_hda_is_supported_format(codec, mout->dig_out_nid, + format) && + !(codec->spdif_status & IEC958_AES0_NONAUDIO)) { + mout->dig_out_used = HDA_DIG_ANALOG_DUP; + /* turn off SPDIF once; otherwise the IEC958 bits won't + * be updated */ + if (codec->spdif_ctls & AC_DIG1_ENABLE) + snd_hda_codec_write(codec, mout->dig_out_nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & + ~AC_DIG1_ENABLE & 0xff); + snd_hda_codec_setup_stream(codec, mout->dig_out_nid, + stream_tag, 0, format); + /* turn on again (if needed) */ + if (codec->spdif_ctls & AC_DIG1_ENABLE) + snd_hda_codec_write(codec, mout->dig_out_nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & 0xff); + } else { + mout->dig_out_used = 0; + snd_hda_codec_setup_stream(codec, mout->dig_out_nid, + 0, 0, 0); + } + } + mutex_unlock(&codec->spdif_mutex); + + /* front */ + snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, + 0, format); + + if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] + && !spec->hp_independent_mode) + /* headphone out will just decode front left/right (stereo) */ + snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, + 0, format); + + /* extra outputs copied from front */ + for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) + if (mout->extra_out_nid[i]) + snd_hda_codec_setup_stream(codec, + mout->extra_out_nid[i], + stream_tag, 0, format); + + /* surrounds */ + for (i = 1; i < mout->num_dacs; i++) { + if (chs >= (i + 1) * 2) /* independent out */ + snd_hda_codec_setup_stream(codec, nids[i], stream_tag, + i * 2, format); + else /* copy front */ + snd_hda_codec_setup_stream(codec, nids[i], stream_tag, + 0, format); + } } static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -1143,36 +1315,18 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; + struct hda_multi_out *mout = &spec->multiout; + const hda_nid_t *nids = mout->dac_nids; - mutex_lock(&spec->config_mutex); - setup_playback_multi_pcm(spec); - snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); - /* remember for dynamic DAC switch with indep-HP */ - spec->active_streams |= STREAM_MULTI_OUT; - spec->cur_dac_stream_tag = stream_tag; - spec->cur_dac_format = format; - mutex_unlock(&spec->config_mutex); - vt1708_start_hp_work(spec); - return 0; -} - -static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - if (spec->hp_independent_mode) - snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, - stream_tag, 0, format); - spec->active_streams |= STREAM_INDEP_HP; - spec->cur_hp_stream_tag = stream_tag; - spec->cur_hp_format = format; - mutex_unlock(&spec->config_mutex); + if (substream->number == 0) + playback_multi_pcm_prep_0(codec, stream_tag, format, + substream); + else { + if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && + spec->hp_independent_mode) + snd_hda_codec_setup_stream(codec, mout->hp_nid, + stream_tag, 0, format); + } vt1708_start_hp_work(spec); return 0; } @@ -1182,26 +1336,37 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; + struct hda_multi_out *mout = &spec->multiout; + const hda_nid_t *nids = mout->dac_nids; + int i; - mutex_lock(&spec->config_mutex); - snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); - spec->active_streams &= ~STREAM_MULTI_OUT; - mutex_unlock(&spec->config_mutex); - vt1708_stop_hp_work(spec); - return 0; -} - -static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - if (spec->hp_independent_mode) - snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, 0, 0, 0); - spec->active_streams &= ~STREAM_INDEP_HP; - mutex_unlock(&spec->config_mutex); + if (substream->number == 0) { + for (i = 0; i < mout->num_dacs; i++) + snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); + + if (mout->hp_nid && !spec->hp_independent_mode) + snd_hda_codec_setup_stream(codec, mout->hp_nid, + 0, 0, 0); + + for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) + if (mout->extra_out_nid[i]) + snd_hda_codec_setup_stream(codec, + mout->extra_out_nid[i], + 0, 0, 0); + mutex_lock(&codec->spdif_mutex); + if (mout->dig_out_nid && + mout->dig_out_used == HDA_DIG_ANALOG_DUP) { + snd_hda_codec_setup_stream(codec, mout->dig_out_nid, + 0, 0, 0); + mout->dig_out_used = 0; + } + mutex_unlock(&codec->spdif_mutex); + } else { + if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && + spec->hp_independent_mode) + snd_hda_codec_setup_stream(codec, mout->hp_nid, + 0, 0, 0); + } vt1708_stop_hp_work(spec); return 0; } @@ -1270,127 +1435,47 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -/* analog capture with dynamic ADC switching */ -static int via_dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - int adc_idx = spec->inputs[spec->cur_mux[0]].adc_idx; - - mutex_lock(&spec->config_mutex); - spec->cur_adc = spec->adc_nids[adc_idx]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - mutex_unlock(&spec->config_mutex); - return 0; -} - -static int via_dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - mutex_unlock(&spec->config_mutex); - return 0; -} - -/* re-setup the stream if running; called from input-src put */ -static bool via_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) -{ - struct via_spec *spec = codec->spec; - int adc_idx = spec->inputs[cur].adc_idx; - hda_nid_t adc = spec->adc_nids[adc_idx]; - bool ret = false; - - mutex_lock(&spec->config_mutex); - if (spec->cur_adc && spec->cur_adc != adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = adc; - snd_hda_codec_setup_stream(codec, adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - ret = true; - } - mutex_unlock(&spec->config_mutex); - return ret; -} - -static const struct hda_pcm_stream via_pcm_analog_playback = { - .substreams = 1, +static const struct hda_pcm_stream vt1708_pcm_analog_playback = { + .substreams = 2, .channels_min = 2, .channels_max = 8, - /* NID is set in via_build_pcms */ + .nid = 0x10, /* NID to query formats and rates */ .ops = { - .open = via_playback_multi_pcm_open, - .close = via_playback_multi_pcm_close, + .open = via_playback_pcm_open, .prepare = via_playback_multi_pcm_prepare, .cleanup = via_playback_multi_pcm_cleanup }, }; -static const struct hda_pcm_stream via_pcm_hp_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .open = via_playback_hp_pcm_open, - .close = via_playback_hp_pcm_close, - .prepare = via_playback_hp_pcm_prepare, - .cleanup = via_playback_hp_pcm_cleanup - }, -}; - static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { - .substreams = 1, + .substreams = 2, .channels_min = 2, .channels_max = 8, - /* NID is set in via_build_pcms */ + .nid = 0x10, /* NID to query formats and rates */ /* We got noisy outputs on the right channel on VT1708 when * 24bit samples are used. Until any workaround is found, * disable the 24bit format, so far. */ .formats = SNDRV_PCM_FMTBIT_S16_LE, .ops = { - .open = via_playback_multi_pcm_open, - .close = via_playback_multi_pcm_close, + .open = via_playback_pcm_open, .prepare = via_playback_multi_pcm_prepare, .cleanup = via_playback_multi_pcm_cleanup }, }; -static const struct hda_pcm_stream via_pcm_analog_capture = { - .substreams = 1, /* will be changed in via_build_pcms() */ +static const struct hda_pcm_stream vt1708_pcm_analog_capture = { + .substreams = 2, .channels_min = 2, .channels_max = 2, - /* NID is set in via_build_pcms */ + .nid = 0x15, /* NID to query formats and rates */ .ops = { .prepare = via_capture_pcm_prepare, .cleanup = via_capture_pcm_cleanup }, }; -static const struct hda_pcm_stream via_pcm_dyn_adc_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .prepare = via_dyn_adc_capture_pcm_prepare, - .cleanup = via_dyn_adc_capture_pcm_cleanup, - }, -}; - -static const struct hda_pcm_stream via_pcm_digital_playback = { +static const struct hda_pcm_stream vt1708_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1403,47 +1488,19 @@ static const struct hda_pcm_stream via_pcm_digital_playback = { }, }; -static const struct hda_pcm_stream via_pcm_digital_capture = { +static const struct hda_pcm_stream vt1708_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, }; -/* - * slave controls for virtual master - */ -static const char * const via_slave_vols[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - "Side Playback Volume", - "Headphone Playback Volume", - "Speaker Playback Volume", - NULL, -}; - -static const char * const via_slave_sws[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - "Side Playback Switch", - "Headphone Playback Switch", - "Speaker Playback Switch", - NULL, -}; - static int via_build_controls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; struct snd_kcontrol *kctl; + const struct snd_kcontrol_new *knew; int err, i; - if (spec->set_widgets_power_state) - if (!via_clone_control(spec, &via_pin_power_ctl_enum)) - return -ENOMEM; - for (i = 0; i < spec->num_mixers; i++) { err = snd_hda_add_new_ctls(codec, spec->mixers[i]); if (err < 0) @@ -1452,7 +1509,6 @@ static int via_build_controls(struct hda_codec *codec) if (spec->multiout.dig_out_nid) { err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, spec->multiout.dig_out_nid); if (err < 0) return err; @@ -1468,23 +1524,6 @@ static int via_build_controls(struct hda_codec *codec) return err; } - /* if we have no master control, let's create it */ - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], - HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, via_slave_vols); - if (err < 0) - return err; - } - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, via_slave_sws); - if (err < 0) - return err; - } - /* assign Capture Source enums to NID */ kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); for (i = 0; kctl && i < kctl->count; i++) { @@ -1493,9 +1532,22 @@ static int via_build_controls(struct hda_codec *codec) return err; } + /* other nid->control mapping */ + for (i = 0; i < spec->num_mixers; i++) { + for (knew = spec->mixers[i]; knew->name; knew++) { + if (knew->iface != NID_MAPPING) + continue; + kctl = snd_hda_find_mixer_ctl(codec, knew->name); + if (kctl == NULL) + continue; + err = snd_hda_add_nid(codec, kctl, 0, + knew->subdevice); + } + } + /* init power states */ set_widgets_power_state(codec); - analog_low_current_mode(codec); + analog_low_current_mode(codec, 1); via_free_kctls(codec); /* no longer needed */ return 0; @@ -1509,71 +1561,36 @@ static int via_build_pcms(struct hda_codec *codec) codec->num_pcms = 1; codec->pcm_info = info; - snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); info->name = spec->stream_name_analog; - - if (!spec->stream_analog_playback) - spec->stream_analog_playback = &via_pcm_analog_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_analog_playback; + *(spec->stream_analog_playback); info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; - if (!spec->stream_analog_capture) { - if (spec->dyn_adc_switch) - spec->stream_analog_capture = - &via_pcm_dyn_adc_analog_capture; - else - spec->stream_analog_capture = &via_pcm_analog_capture; - } - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - *spec->stream_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - if (!spec->dyn_adc_switch) - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids; - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { codec->num_pcms++; info++; - snprintf(spec->stream_name_digital, - sizeof(spec->stream_name_digital), - "%s Digital", codec->chip_name); info->name = spec->stream_name_digital; info->pcm_type = HDA_PCM_TYPE_SPDIF; if (spec->multiout.dig_out_nid) { - if (!spec->stream_digital_playback) - spec->stream_digital_playback = - &via_pcm_digital_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_digital_playback; + *(spec->stream_digital_playback); info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; } if (spec->dig_in_nid) { - if (!spec->stream_digital_capture) - spec->stream_digital_capture = - &via_pcm_digital_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE] = - *spec->stream_digital_capture; + *(spec->stream_digital_capture); info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; } } - if (spec->hp_dac_nid) { - codec->num_pcms++; - info++; - snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp), - "%s HP", codec->chip_name); - info->name = spec->stream_name_hp; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->hp_dac_nid; - } return 0; } @@ -1586,62 +1603,57 @@ static void via_free(struct hda_codec *codec) via_free_kctls(codec); vt1708_stop_hp_work(spec); - kfree(spec->bind_cap_vol); - kfree(spec->bind_cap_sw); - kfree(spec); + kfree(codec->spec); } -/* mute/unmute outputs */ -static void toggle_output_mutes(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, bool mute) +/* mute internal speaker if HP is plugged */ +static void via_hp_automute(struct hda_codec *codec) { - int i; - for (i = 0; i < num_pins; i++) { - unsigned int parm = snd_hda_codec_read(codec, pins[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (parm & AC_PINCTL_IN_EN) - continue; - if (mute) - parm &= ~AC_PINCTL_OUT_EN; - else - parm |= AC_PINCTL_OUT_EN; - snd_hda_codec_write(codec, pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, parm); + unsigned int present = 0; + struct via_spec *spec = codec->spec; + + present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); + + if (!spec->hp_independent_mode) { + struct snd_ctl_elem_id id; + /* auto mute */ + snd_hda_codec_amp_stereo( + codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + /* notify change */ + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, "Front Playback Switch"); + snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, + &id); } } -/* mute internal speaker if line-out is plugged */ -static void via_line_automute(struct hda_codec *codec, int present) +/* mute mono out if HP or Line out is plugged */ +static void via_mono_automute(struct hda_codec *codec) { + unsigned int hp_present, lineout_present; struct via_spec *spec = codec->spec; - if (!spec->autocfg.speaker_outs) + if (spec->codec_type != VT1716S) return; - if (!present) - present = snd_hda_jack_detect(codec, + + lineout_present = snd_hda_jack_detect(codec, spec->autocfg.line_out_pins[0]); - toggle_output_mutes(codec, spec->autocfg.speaker_outs, - spec->autocfg.speaker_pins, - present); -} - -/* mute internal speaker if HP is plugged */ -static void via_hp_automute(struct hda_codec *codec) -{ - int present = 0; - int nums; - struct via_spec *spec = codec->spec; - - if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0]) - present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); - - if (spec->smart51_enabled) - nums = spec->autocfg.line_outs + spec->smart51_nums; - else - nums = spec->autocfg.line_outs; - toggle_output_mutes(codec, nums, spec->autocfg.line_out_pins, present); - - via_line_automute(codec, present); + + /* Mute Mono Out if Line Out is plugged */ + if (lineout_present) { + snd_hda_codec_amp_stereo( + codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE); + return; + } + + hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); + + if (!spec->hp_independent_mode) + snd_hda_codec_amp_stereo( + codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, + hp_present ? HDA_AMP_MUTE : 0); } static void via_gpio_control(struct hda_codec *codec) @@ -1666,9 +1678,9 @@ static void via_gpio_control(struct hda_codec *codec) if (gpio_data == 0x02) { /* unmute line out */ - snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_OUT); + snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0], + HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); + if (vol_counter & 0x20) { /* decrease volume */ if (vol > master_vol) @@ -1685,12 +1697,73 @@ static void via_gpio_control(struct hda_codec *codec) } } else if (!(gpio_data & 0x02)) { /* mute line out */ - snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - 0); + snd_hda_codec_amp_stereo(codec, + spec->autocfg.line_out_pins[0], + HDA_OUTPUT, 0, HDA_AMP_MUTE, + HDA_AMP_MUTE); + } +} + +/* mute Internal-Speaker if HP is plugged */ +static void via_speaker_automute(struct hda_codec *codec) +{ + unsigned int hp_present; + struct via_spec *spec = codec->spec; + + if (!VT2002P_COMPATIBLE(spec)) + return; + + hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); + + if (!spec->hp_independent_mode) { + struct snd_ctl_elem_id id; + snd_hda_codec_amp_stereo( + codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0, + HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0); + /* notify change */ + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, "Speaker Playback Switch"); + snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, + &id); + } +} + +/* mute line-out and internal speaker if HP is plugged */ +static void via_hp_bind_automute(struct hda_codec *codec) +{ + /* use long instead of int below just to avoid an internal compiler + * error with gcc 4.0.x + */ + unsigned long hp_present, present = 0; + struct via_spec *spec = codec->spec; + int i; + + if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0]) + return; + + hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); + + present = snd_hda_jack_detect(codec, spec->autocfg.line_out_pins[0]); + + if (!spec->hp_independent_mode) { + /* Mute Line-Outs */ + for (i = 0; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.line_out_pins[i], + HDA_OUTPUT, 0, + HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0); + if (hp_present) + present = hp_present; } + /* Speakers */ + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } + /* unsolicited event for jack sensing */ static void via_unsol_event(struct hda_codec *codec, unsigned int res) @@ -1702,10 +1775,43 @@ static void via_unsol_event(struct hda_codec *codec, res &= ~VIA_JACK_EVENT; - if (res == VIA_HP_EVENT || res == VIA_LINE_EVENT) + if (res == VIA_HP_EVENT) via_hp_automute(codec); else if (res == VIA_GPIO_EVENT) via_gpio_control(codec); + else if (res == VIA_MONO_EVENT) + via_mono_automute(codec); + else if (res == VIA_SPEAKER_EVENT) + via_speaker_automute(codec); + else if (res == VIA_BIND_HP_EVENT) + via_hp_bind_automute(codec); +} + +static int via_init(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int i; + for (i = 0; i < spec->num_iverbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); + + /* Lydia Add for EAPD enable */ + if (!spec->dig_in_nid) { /* No Digital In connection */ + if (spec->dig_in_pin) { + snd_hda_codec_write(codec, spec->dig_in_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + snd_hda_codec_write(codec, spec->dig_in_pin, 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x02); + } + } else /* enable SPDIF-input pin */ + snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); + + /* assign slave outs */ + if (spec->slave_dig_outs[0]) + codec->slave_dig_outs = spec->slave_dig_outs; + + return 0; } #ifdef SND_HDA_NEEDS_RESUME @@ -1727,15 +1833,11 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) /* */ - -static int via_init(struct hda_codec *codec); - static const struct hda_codec_ops via_patch_ops = { .build_controls = via_build_controls, .build_pcms = via_build_pcms, .init = via_init, .free = via_free, - .unsol_event = via_unsol_event, #ifdef SND_HDA_NEEDS_RESUME .suspend = via_suspend, #endif @@ -1744,899 +1846,803 @@ static const struct hda_codec_ops via_patch_ops = { #endif }; -static bool is_empty_dac(struct hda_codec *codec, hda_nid_t dac) +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1708_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec = codec->spec; int i; + hda_nid_t nid; - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (spec->multiout.dac_nids[i] == dac) - return false; - } - if (spec->hp_dac_nid == dac) - return false; - return true; -} - -static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t target_dac, int with_aa_mix, - struct nid_path *path, int depth) -{ - struct via_spec *spec = codec->spec; - hda_nid_t conn[8]; - int i, nums; + spec->multiout.num_dacs = cfg->line_outs; - if (nid == spec->aa_mix_nid) { - if (!with_aa_mix) - return false; - with_aa_mix = 2; /* mark aa-mix is included */ - } + spec->multiout.dac_nids = spec->private_dac_nids; - nums = snd_hda_get_connections(codec, nid, conn, ARRAY_SIZE(conn)); - for (i = 0; i < nums; i++) { - if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT) - continue; - if (conn[i] == target_dac || is_empty_dac(codec, conn[i])) { - /* aa-mix is requested but not included? */ - if (!(spec->aa_mix_nid && with_aa_mix == 1)) - goto found; + for (i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + spec->private_dac_nids[i] = 0x12; + break; + case AUTO_SEQ_SURROUND: + spec->private_dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: + spec->private_dac_nids[i] = 0x13; + break; + } } } - if (depth >= MAX_NID_PATH_DEPTH) - return false; - for (i = 0; i < nums; i++) { - unsigned int type; - type = get_wcaps_type(get_wcaps(codec, conn[i])); - if (type == AC_WID_AUD_OUT) - continue; - if (__parse_output_path(codec, conn[i], target_dac, - with_aa_mix, path, depth + 1)) - goto found; - } - return false; - - found: - path->path[path->depth] = conn[i]; - path->idx[path->depth] = i; - if (nums > 1 && get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX) - path->multi[path->depth] = 1; - path->depth++; - return true; -} -static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t target_dac, int with_aa_mix, - struct nid_path *path) -{ - if (__parse_output_path(codec, nid, target_dac, with_aa_mix, path, 1)) { - path->path[path->depth] = nid; - path->depth++; - snd_printdd("output-path: depth=%d, %02x/%02x/%02x/%02x/%02x\n", - path->depth, path->path[0], path->path[1], - path->path[2], path->path[3], path->path[4]); - return true; - } - return false; + return 0; } -static int via_auto_fill_dac_nids(struct hda_codec *codec) +/* add playback controls from the parsed DAC table */ +static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i, dac_num; - hda_nid_t nid; + char name[32]; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; + hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b}; + int i, err; - spec->multiout.dac_nids = spec->private_dac_nids; - dac_num = 0; - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t dac = 0; + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { nid = cfg->line_out_pins[i]; + if (!nid) continue; - if (parse_output_path(codec, nid, 0, 0, &spec->out_path[i])) - dac = spec->out_path[i].path[0]; - if (!i && parse_output_path(codec, nid, dac, 1, - &spec->out_mix_path)) - dac = spec->out_mix_path.path[0]; - if (dac) { - spec->private_dac_nids[i] = dac; - dac_num++; - } - } - if (!spec->out_path[0].depth && spec->out_mix_path.depth) { - spec->out_path[0] = spec->out_mix_path; - spec->out_mix_path.depth = 0; - } - spec->multiout.num_dacs = dac_num; - return 0; -} -static int create_ch_ctls(struct hda_codec *codec, const char *pfx, - int chs, bool check_dac, struct nid_path *path) -{ - struct via_spec *spec = codec->spec; - char name[32]; - hda_nid_t dac, pin, sel, nid; - int err; + nid_vol = nid_vols[i]; - dac = check_dac ? path->path[0] : 0; - pin = path->path[path->depth - 1]; - sel = path->depth > 1 ? path->path[1] : 0; + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; - if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = dac; - else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = pin; - else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = sel; - else - nid = 0; - if (nid) { - sprintf(name, "%s Playback Volume", pfx); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - path->vol_ctl = nid; + /* add control to PW3 */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } } - if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = dac; - else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = pin; - else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = sel; - else - nid = 0; - if (nid) { - sprintf(name, "%s Playback Switch", pfx); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - path->mute_ctl = nid; - } return 0; } -static void mangle_smart51(struct hda_codec *codec) +static void create_hp_imux(struct via_spec *spec) { - struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct auto_pin_cfg_item *ins = cfg->inputs; - int i, j, nums, attr; - int pins[AUTO_CFG_MAX_INS]; + int i; + struct hda_input_mux *imux = &spec->private_imux[1]; + static const char * const texts[] = { "OFF", "ON", NULL}; - for (attr = INPUT_PIN_ATTR_REAR; attr >= INPUT_PIN_ATTR_NORMAL; attr--) { - nums = 0; - for (i = 0; i < cfg->num_inputs; i++) { - unsigned int def; - if (ins[i].type > AUTO_PIN_LINE_IN) - continue; - def = snd_hda_codec_get_pincfg(codec, ins[i].pin); - if (snd_hda_get_input_pin_attr(def) != attr) - continue; - for (j = 0; j < nums; j++) - if (ins[pins[j]].type < ins[i].type) { - memmove(pins + j + 1, pins + j, - (nums - j) * sizeof(int)); - break; - } - pins[j] = i; - nums++; - } - if (cfg->line_outs + nums < 3) - continue; - for (i = 0; i < nums; i++) { - hda_nid_t pin = ins[pins[i]].pin; - spec->smart51_pins[spec->smart51_nums++] = pin; - cfg->line_out_pins[cfg->line_outs++] = pin; - if (cfg->line_outs == 3) - break; - } - return; - } -} + /* for hp mode select */ + for (i = 0; texts[i]; i++) + snd_hda_add_imux_item(imux, texts[i], i, NULL); -static void copy_path_mixer_ctls(struct nid_path *dst, struct nid_path *src) -{ - dst->vol_ctl = src->vol_ctl; - dst->mute_ctl = src->mute_ctl; + spec->hp_mux = &spec->private_imux[1]; } -/* add playback controls from the parsed DAC table */ -static int via_auto_create_multi_out_ctls(struct hda_codec *codec) +static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) { - struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct nid_path *path; - static const char * const chname[4] = { - "Front", "Surround", "C/LFE", "Side" - }; - int i, idx, err; - int old_line_outs; + int err; + + if (!pin) + return 0; - /* check smart51 */ - old_line_outs = cfg->line_outs; - if (cfg->line_outs == 1) - mangle_smart51(codec); + spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */ + spec->hp_independent_mode_index = 1; - err = via_auto_fill_dac_nids(codec); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - if (spec->multiout.num_dacs < 3) { - spec->smart51_nums = 0; - cfg->line_outs = old_line_outs; - } - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t pin, dac; - pin = cfg->line_out_pins[i]; - dac = spec->multiout.dac_nids[i]; - if (!pin || !dac) - continue; - path = spec->out_path + i; - if (i == HDA_CLFE) { - err = create_ch_ctls(codec, "Center", 1, true, path); - if (err < 0) - return err; - err = create_ch_ctls(codec, "LFE", 2, true, path); - if (err < 0) - return err; - } else { - const char *pfx = chname[i]; - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && - cfg->line_outs == 1) - pfx = "Speaker"; - err = create_ch_ctls(codec, pfx, 3, true, path); - if (err < 0) - return err; - } - if (path != spec->out_path + i) - copy_path_mixer_ctls(&spec->out_path[i], path); - if (path == spec->out_path && spec->out_mix_path.depth) - copy_path_mixer_ctls(&spec->out_mix_path, path); - } - - idx = get_connection_index(codec, spec->aa_mix_nid, - spec->multiout.dac_nids[0]); - if (idx >= 0) { - /* add control to mixer */ - const char *name; - name = spec->out_mix_path.depth ? - "PCM Loopback Playback Volume" : "PCM Playback Volume"; - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, - idx, HDA_INPUT)); - if (err < 0) - return err; - name = spec->out_mix_path.depth ? - "PCM Loopback Playback Switch" : "PCM Playback Switch"; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, - idx, HDA_INPUT)); - if (err < 0) - return err; - } - - cfg->line_outs = old_line_outs; + create_hp_imux(spec); return 0; } -static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) +/* create playback/capture controls for input pins */ +static int vt_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + hda_nid_t cap_nid, + const hda_nid_t pin_idxs[], + int num_idxs) { struct via_spec *spec = codec->spec; - struct nid_path *path; - bool check_dac; - int i, err; - - if (!pin) - return 0; + struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx, type, type_idx = 0; - if (!parse_output_path(codec, pin, 0, 0, &spec->hp_indep_path)) { - for (i = HDA_SIDE; i >= HDA_CLFE; i--) { - if (i < spec->multiout.num_dacs && - parse_output_path(codec, pin, - spec->multiout.dac_nids[i], 0, - &spec->hp_indep_path)) { - spec->hp_indep_shared = i; - break; - } + /* for internal loopback recording select */ + for (idx = 0; idx < num_idxs; idx++) { + if (pin_idxs[idx] == 0xff) { + snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL); + break; } } - if (spec->hp_indep_path.depth) { - spec->hp_dac_nid = spec->hp_indep_path.path[0]; - if (!spec->hp_indep_shared) - spec->hp_path = spec->hp_indep_path; - } - /* optionally check front-path w/o AA-mix */ - if (!spec->hp_path.depth) - parse_output_path(codec, pin, - spec->multiout.dac_nids[HDA_FRONT], 0, - &spec->hp_path); - - if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], - 1, &spec->hp_mix_path) && !spec->hp_path.depth) - return 0; - if (spec->hp_path.depth) { - path = &spec->hp_path; - check_dac = true; - } else { - path = &spec->hp_mix_path; - check_dac = false; + for (i = 0; i < cfg->num_inputs; i++) { + const char *label; + type = cfg->inputs[i].type; + for (idx = 0; idx < num_idxs; idx++) + if (pin_idxs[idx] == cfg->inputs[i].pin) + break; + if (idx >= num_idxs) + continue; + if (i > 0 && type == cfg->inputs[i - 1].type) + type_idx++; + else + type_idx = 0; + label = hda_get_autocfg_input_label(codec, cfg, i); + if (spec->codec_type == VT1708S || + spec->codec_type == VT1702 || + spec->codec_type == VT1716S) + err = via_new_analog_input(spec, label, type_idx, + idx+1, cap_nid); + else + err = via_new_analog_input(spec, label, type_idx, + idx, cap_nid); + if (err < 0) + return err; + snd_hda_add_imux_item(imux, label, idx, NULL); } - err = create_ch_ctls(codec, "Headphone", 3, check_dac, path); - if (err < 0) - return err; - if (check_dac) - copy_path_mixer_ctls(&spec->hp_mix_path, path); - else - copy_path_mixer_ctls(&spec->hp_path, path); - if (spec->hp_indep_path.depth) - copy_path_mixer_ctls(&spec->hp_indep_path, path); return 0; } -static int via_auto_create_speaker_ctls(struct hda_codec *codec) +/* create playback/capture controls for input pins */ +static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec = codec->spec; - struct nid_path *path; - bool check_dac; - hda_nid_t pin, dac; - int err; - - pin = spec->autocfg.speaker_pins[0]; - if (!spec->autocfg.speaker_outs || !pin) - return 0; + static const hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} - if (parse_output_path(codec, pin, 0, 0, &spec->speaker_path)) - dac = spec->speaker_path.path[0]; - if (!dac) - parse_output_path(codec, pin, - spec->multiout.dac_nids[HDA_FRONT], 0, - &spec->speaker_path); - if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], - 1, &spec->speaker_mix_path) && !dac) - return 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1708_loopbacks[] = { + { 0x17, HDA_INPUT, 1 }, + { 0x17, HDA_INPUT, 2 }, + { 0x17, HDA_INPUT, 3 }, + { 0x17, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif - /* no AA-path for front? */ - if (!spec->out_mix_path.depth && spec->speaker_mix_path.depth) - dac = 0; +static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int def_conf; + unsigned char seqassoc; - spec->speaker_dac_nid = dac; - spec->multiout.extra_out_nid[0] = dac; - if (dac) { - path = &spec->speaker_path; - check_dac = true; - } else { - path = &spec->speaker_mix_path; - check_dac = false; + def_conf = snd_hda_codec_get_pincfg(codec, nid); + seqassoc = (unsigned char) get_defcfg_association(def_conf); + seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE + && (seqassoc == 0xf0 || seqassoc == 0xff)) { + def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); + snd_hda_codec_set_pincfg(codec, nid, def_conf); } - err = create_ch_ctls(codec, "Speaker", 3, check_dac, path); - if (err < 0) - return err; - if (check_dac) - copy_path_mixer_ctls(&spec->speaker_mix_path, path); - else - copy_path_mixer_ctls(&spec->speaker_path, path); - return 0; -} -#define via_aamix_ctl_info via_pin_power_ctl_info + return; +} -static int via_aamix_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->aamix_mode; - return 0; -} -static void update_aamix_paths(struct hda_codec *codec, int do_mix, - struct nid_path *nomix, struct nid_path *mix) -{ - if (do_mix) { - activate_output_path(codec, nomix, false, false); - activate_output_path(codec, mix, true, false); - } else { - activate_output_path(codec, mix, false, false); - activate_output_path(codec, nomix, true, false); - } + if (spec->codec_type != VT1708) + return 0; + spec->vt1708_jack_detectect = + !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1); + ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect; + return 0; } -static int via_aamix_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - unsigned int val = ucontrol->value.enumerated.item[0]; + int change; - if (val == spec->aamix_mode) + if (spec->codec_type != VT1708) return 0; - spec->aamix_mode = val; - /* update front path */ - update_aamix_paths(codec, val, &spec->out_path[0], &spec->out_mix_path); - /* update HP path */ - if (!spec->hp_independent_mode) { - update_aamix_paths(codec, val, &spec->hp_path, - &spec->hp_mix_path); + spec->vt1708_jack_detectect = ucontrol->value.integer.value[0]; + change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8)) + == !spec->vt1708_jack_detectect; + if (spec->vt1708_jack_detectect) { + mute_aa_path(codec, 1); + notify_aa_path_ctls(codec); } - /* update speaker path */ - update_aamix_paths(codec, val, &spec->speaker_path, - &spec->speaker_mix_path); - return 1; + return change; } -static const struct snd_kcontrol_new via_aamix_ctl_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Loopback Mixing", - .info = via_aamix_ctl_info, - .get = via_aamix_ctl_get, - .put = via_aamix_ctl_put, +static const struct snd_kcontrol_new vt1708_jack_detectect[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Jack Detect", + .count = 1, + .info = snd_ctl_boolean_mono_info, + .get = vt1708_jack_detectect_get, + .put = vt1708_jack_detectect_put, + }, + {} /* end */ }; -static int via_auto_create_loopback_switch(struct hda_codec *codec) +static int vt1708_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; + int err; - if (!spec->aa_mix_nid || !spec->out_mix_path.depth) - return 0; /* no loopback switching available */ - if (!via_clone_control(spec, &via_aamix_ctl_enum)) - return -ENOMEM; - return 0; -} - -/* look for ADCs */ -static int via_fill_adcs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t nid = codec->start_nid; - int i; + /* Add HP and CD pin config connect bit re-config action */ + vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); + vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID); - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) - continue; - if (wcaps & AC_WCAP_DIGITAL) - continue; - if (!(wcaps & AC_WCAP_CONN_LIST)) - continue; - if (spec->num_adc_nids >= ARRAY_SIZE(spec->adc_nids)) - return -ENOMEM; - spec->adc_nids[spec->num_adc_nids++] = nid; - } - return 0; -} + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ -/* input-src control */ -static int via_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; + err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + /* add jack detect on/off control */ + err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect); + if (err < 0) + return err; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->num_inputs; - if (uinfo->value.enumerated.item >= spec->num_inputs) - uinfo->value.enumerated.item = spec->num_inputs - 1; - strcpy(uinfo->value.enumerated.name, - spec->inputs[uinfo->value.enumerated.item].label); - return 0; -} + spec->multiout.max_channels = spec->multiout.num_dacs * 2; -static int via_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + if (spec->autocfg.dig_outs) + spec->multiout.dig_out_nid = VT1708_DIGOUT_NID; + spec->dig_in_pin = VT1708_DIGIN_PIN; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = VT1708_DIGIN_NID; - ucontrol->value.enumerated.item[0] = spec->cur_mux[idx]; - return 0; -} + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; -static int via_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - hda_nid_t mux; - int cur; + spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs; - cur = ucontrol->value.enumerated.item[0]; - if (cur < 0 || cur >= spec->num_inputs) - return -EINVAL; - if (spec->cur_mux[idx] == cur) - return 0; - spec->cur_mux[idx] = cur; - if (spec->dyn_adc_switch) { - int adc_idx = spec->inputs[cur].adc_idx; - mux = spec->mux_nids[adc_idx]; - via_dyn_adc_pcm_resetup(codec, cur); - } else { - mux = spec->mux_nids[idx]; - if (snd_BUG_ON(!mux)) - return -EINVAL; - } + spec->input_mux = &spec->private_imux[0]; - if (mux) { - /* switch to D0 beofre change index */ - if (snd_hda_codec_read(codec, mux, 0, - AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0) - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_CONNECT_SEL, - spec->inputs[cur].mux_idx); - } + if (spec->hp_mux) + via_hp_build(codec); - /* update jack power state */ - set_widgets_power_state(codec); - return 0; + via_smart51_build(spec); + return 1; } -static const struct snd_kcontrol_new via_input_src_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .info = via_mux_enum_info, - .get = via_mux_enum_get, - .put = via_mux_enum_put, -}; - -static int create_input_src_ctls(struct hda_codec *codec, int count) +/* init callback for auto-configuration model -- overriding the default init */ +static int via_auto_init(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - if (spec->num_inputs <= 1 || !count) - return 0; /* no need for single src */ + via_init(codec); + via_auto_init_multi_out(codec); + via_auto_init_hp_out(codec); + via_auto_init_analog_input(codec); + + if (VT2002P_COMPATIBLE(spec)) { + via_hp_bind_automute(codec); + } else { + via_hp_automute(codec); + via_speaker_automute(codec); + } - knew = via_clone_control(spec, &via_input_src_ctl); - if (!knew) - return -ENOMEM; - knew->count = count; return 0; } -/* add the powersave loopback-list entry */ -static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) +static void vt1708_update_hp_jack_state(struct work_struct *work) { - struct hda_amp_list *list; - - if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) + struct via_spec *spec = container_of(work, struct via_spec, + vt1708_hp_work.work); + if (spec->codec_type != VT1708) return; - list = spec->loopback_list + spec->num_loopbacks; - list->nid = mix; - list->dir = HDA_INPUT; - list->idx = idx; - spec->num_loopbacks++; - spec->loopback.amplist = spec->loopback_list; -} - -static bool is_reachable_nid(struct hda_codec *codec, hda_nid_t src, - hda_nid_t dst) -{ - return snd_hda_get_conn_index(codec, src, dst, 1) >= 0; + /* if jack state toggled */ + if (spec->vt1708_hp_present + != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) { + spec->vt1708_hp_present ^= 1; + via_hp_automute(spec->codec); + } + vt1708_start_hp_work(spec); } -/* add the input-route to the given pin */ -static bool add_input_route(struct hda_codec *codec, hda_nid_t pin) +static int get_mux_nids(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - int c, idx; + hda_nid_t nid, conn[8]; + unsigned int type; + int i, n; - spec->inputs[spec->num_inputs].adc_idx = -1; - spec->inputs[spec->num_inputs].pin = pin; - for (c = 0; c < spec->num_adc_nids; c++) { - if (spec->mux_nids[c]) { - idx = get_connection_index(codec, spec->mux_nids[c], - pin); - if (idx < 0) - continue; - spec->inputs[spec->num_inputs].mux_idx = idx; - } else { - if (!is_reachable_nid(codec, spec->adc_nids[c], pin)) - continue; - } - spec->inputs[spec->num_inputs].adc_idx = c; - /* Can primary ADC satisfy all inputs? */ - if (!spec->dyn_adc_switch && - spec->num_inputs > 0 && spec->inputs[0].adc_idx != c) { - snd_printd(KERN_INFO - "via: dynamic ADC switching enabled\n"); - spec->dyn_adc_switch = 1; + for (i = 0; i < spec->num_adc_nids; i++) { + nid = spec->adc_nids[i]; + while (nid) { + type = get_wcaps_type(get_wcaps(codec, nid)); + if (type == AC_WID_PIN) + break; + n = snd_hda_get_connections(codec, nid, conn, + ARRAY_SIZE(conn)); + if (n <= 0) + break; + if (n > 1) { + spec->mux_nids[i] = nid; + break; + } + nid = conn[0]; } - return true; } - return false; + return 0; } -static int get_mux_nids(struct hda_codec *codec); - -/* parse input-routes; fill ADCs, MUXs and input-src entries */ -static int parse_analog_inputs(struct hda_codec *codec) +static int patch_vt1708(struct hda_codec *codec) { - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; + struct via_spec *spec; + int err; - err = via_fill_adcs(codec); - if (err < 0) - return err; - err = get_mux_nids(codec); - if (err < 0) + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; + + /* automatic parse from the BIOS config */ + err = vt1708_parse_auto_config(codec); + if (err < 0) { + via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } - /* fill all input-routes */ - for (i = 0; i < cfg->num_inputs; i++) { - if (add_input_route(codec, cfg->inputs[i].pin)) - spec->inputs[spec->num_inputs++].label = - hda_get_autocfg_input_label(codec, cfg, i); + + spec->stream_name_analog = "VT1708 Analog"; + spec->stream_analog_playback = &vt1708_pcm_analog_playback; + /* disable 32bit format on VT1708 */ + if (codec->vendor_id == 0x11061708) + spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback; + spec->stream_analog_capture = &vt1708_pcm_analog_capture; + + spec->stream_name_digital = "VT1708 Digital"; + spec->stream_digital_playback = &vt1708_pcm_digital_playback; + spec->stream_digital_capture = &vt1708_pcm_digital_capture; + + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1708_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1708_capture_mixer; + spec->num_mixers++; } - /* check for internal loopback recording */ - if (spec->aa_mix_nid && - add_input_route(codec, spec->aa_mix_nid)) - spec->inputs[spec->num_inputs++].label = "Stereo Mixer"; + codec->patch_ops = via_patch_ops; + codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708_loopbacks; +#endif + INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); return 0; } -/* create analog-loopback volume/switch controls */ -static int create_loopback_ctls(struct hda_codec *codec) +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1709_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt1709_uniwill_init_verbs[] = { + {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + { } +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb vt1709_10ch_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output selector (0x1a, 0x1b, 0x29) + */ + /* set vol=0 to output mixers */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* + * Unmute PW3 and PW4 + */ + {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Set input of PW4 as MW0 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0}, + /* PW9 Output enable */ + {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + { } +}; + +static const struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 10, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + }, +}; + +static const struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + }, +}; + +static const struct hda_pcm_stream vt1709_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x14, /* NID to query formats and rates */ + .ops = { + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream vt1709_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close + }, +}; + +static const struct hda_pcm_stream vt1709_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +static int vt1709_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - const char *prev_label = NULL; - int type_idx = 0; - int i, j, err, idx; + int i; + hda_nid_t nid; - if (!spec->aa_mix_nid) - return 0; + if (cfg->line_outs == 4) /* 10 channels */ + spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */ + else if (cfg->line_outs == 3) /* 6 channels */ + spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */ - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - const char *label = hda_get_autocfg_input_label(codec, cfg, i); + spec->multiout.dac_nids = spec->private_dac_nids; - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; - idx = get_connection_index(codec, spec->aa_mix_nid, pin); - if (idx >= 0) { - err = via_new_analog_input(spec, label, type_idx, - idx, spec->aa_mix_nid); - if (err < 0) - return err; - add_loopback_list(spec, spec->aa_mix_nid, idx); + if (cfg->line_outs == 4) { /* 10 channels */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + /* AOW0 */ + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + /* AOW2 */ + spec->private_dac_nids[i] = 0x12; + break; + case AUTO_SEQ_SURROUND: + /* AOW3 */ + spec->private_dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: + /* AOW1 */ + spec->private_dac_nids[i] = 0x27; + break; + default: + break; + } + } } - - /* remember the label for smart51 control */ - for (j = 0; j < spec->smart51_nums; j++) { - if (spec->smart51_pins[j] == pin) { - spec->smart51_idxs[j] = idx; - spec->smart51_labels[j] = label; - break; + spec->private_dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ + + } else if (cfg->line_outs == 3) { /* 6 channels */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + /* AOW0 */ + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + /* AOW2 */ + spec->private_dac_nids[i] = 0x12; + break; + case AUTO_SEQ_SURROUND: + /* AOW1 */ + spec->private_dac_nids[i] = 0x11; + break; + default: + break; + } } } } + return 0; } -/* create mic-boost controls (if present) */ -static int create_mic_boost_ctls(struct hda_codec *codec) +/* add playback controls from the parsed DAC table */ +static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; + char name[32]; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; + hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29}; int i, err; - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - unsigned int caps; - const char *label; - char name[32]; + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; - if (cfg->inputs[i].type != AUTO_PIN_MIC) - continue; - caps = query_amp_caps(codec, pin, HDA_INPUT); - if (caps == -1 || !(caps & AC_AMPCAP_NUM_STEPS)) + if (!nid) continue; - label = hda_get_autocfg_input_label(codec, cfg, i); - snprintf(name, sizeof(name), "%s Boost Volume", label); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - } - return 0; -} -/* create capture and input-src controls for multiple streams */ -static int create_multi_adc_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i, err; + nid_vol = nid_vols[i]; - /* create capture mixer elements */ - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t adc = spec->adc_nids[i]; - err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Capture Volume", i, - HDA_COMPOSE_AMP_VAL(adc, 3, 0, - HDA_INPUT)); - if (err < 0) - return err; - err = __via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "Capture Switch", i, - HDA_COMPOSE_AMP_VAL(adc, 3, 0, - HDA_INPUT)); - if (err < 0) - return err; - } - - /* input-source control */ - for (i = 0; i < spec->num_adc_nids; i++) - if (!spec->mux_nids[i]) - break; - err = create_input_src_ctls(codec, i); - if (err < 0) - return err; - return 0; -} - -/* bind capture volume/switch */ -static struct snd_kcontrol_new via_bind_cap_vol_ctl = - HDA_BIND_VOL("Capture Volume", 0); -static struct snd_kcontrol_new via_bind_cap_sw_ctl = - HDA_BIND_SW("Capture Switch", 0); + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* ADD control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; -static int init_bind_ctl(struct via_spec *spec, struct hda_bind_ctls **ctl_ret, - struct hda_ctl_ops *ops) -{ - struct hda_bind_ctls *ctl; - int i; + /* add control to PW3 */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_SURROUND) { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_SIDE) { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } - ctl = kzalloc(sizeof(*ctl) + sizeof(long) * 4, GFP_KERNEL); - if (!ctl) - return -ENOMEM; - ctl->ops = ops; - for (i = 0; i < spec->num_adc_nids; i++) - ctl->values[i] = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], 3, 0, HDA_INPUT); - *ctl_ret = ctl; return 0; } -/* create capture and input-src controls for dynamic ADC-switch case */ -static int create_dyn_adc_ctls(struct hda_codec *codec) +static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) { - struct via_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; int err; - /* set up the bind capture ctls */ - err = init_bind_ctl(spec, &spec->bind_cap_vol, &snd_hda_bind_vol); - if (err < 0) - return err; - err = init_bind_ctl(spec, &spec->bind_cap_sw, &snd_hda_bind_sw); - if (err < 0) - return err; - - /* create capture mixer elements */ - knew = via_clone_control(spec, &via_bind_cap_vol_ctl); - if (!knew) - return -ENOMEM; - knew->private_value = (long)spec->bind_cap_vol; - - knew = via_clone_control(spec, &via_bind_cap_sw_ctl); - if (!knew) - return -ENOMEM; - knew->private_value = (long)spec->bind_cap_sw; - - /* input-source control */ - err = create_input_src_ctls(codec, 1); - if (err < 0) - return err; - return 0; -} + if (!pin) + return 0; -/* parse and create capture-related stuff */ -static int via_auto_create_analog_input_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int err; + if (spec->multiout.num_dacs == 5) /* 10 channels */ + spec->multiout.hp_nid = VT1709_HP_DAC_NID; + else if (spec->multiout.num_dacs == 3) /* 6 channels */ + spec->multiout.hp_nid = 0; + spec->hp_independent_mode_index = 1; - err = parse_analog_inputs(codec); - if (err < 0) - return err; - if (spec->dyn_adc_switch) - err = create_dyn_adc_ctls(codec); - else - err = create_multi_adc_ctls(codec); - if (err < 0) - return err; - err = create_loopback_ctls(codec); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - err = create_mic_boost_ctls(codec); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - return 0; -} - -static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int def_conf; - unsigned char seqassoc; - - def_conf = snd_hda_codec_get_pincfg(codec, nid); - seqassoc = (unsigned char) get_defcfg_association(def_conf); - seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE - && (seqassoc == 0xf0 || seqassoc == 0xff)) { - def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); - snd_hda_codec_set_pincfg(codec, nid, def_conf); - } - - return; -} - -static int vt1708_jack_detect_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - if (spec->codec_type != VT1708) - return 0; - spec->vt1708_jack_detect = - !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1); - ucontrol->value.integer.value[0] = spec->vt1708_jack_detect; return 0; } -static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* create playback/capture controls for input pins */ +static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - int change; - - if (spec->codec_type != VT1708) - return 0; - spec->vt1708_jack_detect = ucontrol->value.integer.value[0]; - change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8)) - == !spec->vt1708_jack_detect; - if (spec->vt1708_jack_detect) { - mute_aa_path(codec, 1); - notify_aa_path_ctls(codec); - } - return change; + static const hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs, + ARRAY_SIZE(pin_idxs)); } -static const struct snd_kcontrol_new vt1708_jack_detect_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Jack Detect", - .count = 1, - .info = snd_ctl_boolean_mono_info, - .get = vt1708_jack_detect_get, - .put = vt1708_jack_detect_put, -}; - -static void fill_dig_outs(struct hda_codec *codec); -static void fill_dig_in(struct hda_codec *codec); - -static int via_parse_auto_config(struct hda_codec *codec) +static int vt1709_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int err; @@ -2644,167 +2650,145 @@ static int via_parse_auto_config(struct hda_codec *codec) err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); if (err < 0) return err; - if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) - return -EINVAL; - - err = via_auto_create_multi_out_ctls(codec); - if (err < 0) - return err; - err = via_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]); + err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg); if (err < 0) return err; - err = via_auto_create_speaker_ctls(codec); + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; - err = via_auto_create_loopback_switch(codec); + err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = via_auto_create_analog_input_ctls(codec); + err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; spec->multiout.max_channels = spec->multiout.num_dacs * 2; - fill_dig_outs(codec); - fill_dig_in(codec); + if (spec->autocfg.dig_outs) + spec->multiout.dig_out_nid = VT1709_DIGOUT_NID; + spec->dig_in_pin = VT1709_DIGIN_PIN; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = VT1709_DIGIN_NID; if (spec->kctls.list) spec->mixers[spec->num_mixers++] = spec->kctls.list; + spec->input_mux = &spec->private_imux[0]; - if (spec->hp_dac_nid && spec->hp_mix_path.depth) { - err = via_hp_build(codec); - if (err < 0) - return err; - } - - err = via_smart51_build(codec); - if (err < 0) - return err; - - /* assign slave outs */ - if (spec->slave_dig_outs[0]) - codec->slave_dig_outs = spec->slave_dig_outs; + if (spec->hp_mux) + via_hp_build(codec); + via_smart51_build(spec); return 1; } -static void via_auto_init_dig_outs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - if (spec->multiout.dig_out_nid) - init_output_pin(codec, spec->autocfg.dig_out_pins[0], PIN_OUT); - if (spec->slave_dig_outs[0]) - init_output_pin(codec, spec->autocfg.dig_out_pins[1], PIN_OUT); -} - -static void via_auto_init_dig_in(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - if (!spec->dig_in_nid) - return; - snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); -} +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1709_loopbacks[] = { + { 0x18, HDA_INPUT, 1 }, + { 0x18, HDA_INPUT, 2 }, + { 0x18, HDA_INPUT, 3 }, + { 0x18, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif -/* initialize the unsolicited events */ -static void via_auto_init_unsol_event(struct hda_codec *codec) +static int patch_vt1709_10ch(struct hda_codec *codec) { - struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int ev; - int i; + struct via_spec *spec; + int err; - if (cfg->hp_pins[0] && is_jack_detectable(codec, cfg->hp_pins[0])) - snd_hda_codec_write(codec, cfg->hp_pins[0], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT); + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; - if (cfg->speaker_pins[0]) - ev = VIA_LINE_EVENT; - else - ev = 0; - for (i = 0; i < cfg->line_outs; i++) { - if (cfg->line_out_pins[i] && - is_jack_detectable(codec, cfg->line_out_pins[i])) - snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ev | VIA_JACK_EVENT); + err = vt1709_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration. " + "Using genenic mode...\n"); } - for (i = 0; i < cfg->num_inputs; i++) { - if (is_jack_detectable(codec, cfg->inputs[i].pin)) - snd_hda_codec_write(codec, cfg->inputs[i].pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | VIA_JACK_EVENT); - } -} + spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs; -static int via_init(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; + spec->stream_name_analog = "VT1709 Analog"; + spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; + spec->stream_analog_capture = &vt1709_pcm_analog_capture; - for (i = 0; i < spec->num_iverbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); + spec->stream_name_digital = "VT1709 Digital"; + spec->stream_digital_playback = &vt1709_pcm_digital_playback; + spec->stream_digital_capture = &vt1709_pcm_digital_capture; - via_auto_init_multi_out(codec); - via_auto_init_hp_out(codec); - via_auto_init_speaker_out(codec); - via_auto_init_analog_input(codec); - via_auto_init_dig_outs(codec); - via_auto_init_dig_in(codec); - via_auto_init_unsol_event(codec); + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1709_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1709_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; - via_hp_automute(codec); + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; +#endif return 0; } +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb vt1709_6ch_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, -static void vt1708_update_hp_jack_state(struct work_struct *work) -{ - struct via_spec *spec = container_of(work, struct via_spec, - vt1708_hp_work.work); - if (spec->codec_type != VT1708) - return; - /* if jack state toggled */ - if (spec->vt1708_hp_present - != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) { - spec->vt1708_hp_present ^= 1; - via_hp_automute(spec->codec); - } - vt1708_start_hp_work(spec); -} -static int get_mux_nids(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t nid, conn[8]; - unsigned int type; - int i, n; + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output selector (0x1a, 0x1b, 0x29) + */ + /* set vol=0 to output mixers */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - for (i = 0; i < spec->num_adc_nids; i++) { - nid = spec->adc_nids[i]; - while (nid) { - type = get_wcaps_type(get_wcaps(codec, nid)); - if (type == AC_WID_PIN) - break; - n = snd_hda_get_connections(codec, nid, conn, - ARRAY_SIZE(conn)); - if (n <= 0) - break; - if (n > 1) { - spec->mux_nids[i] = nid; - break; - } - nid = conn[0]; - } - } - return 0; -} + /* + * Unmute PW3 and PW4 + */ + {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, -static int patch_vt1708(struct hda_codec *codec) + /* Set input of PW4 as MW0 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0}, + /* PW9 Output enable */ + {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + { } +}; + +static int patch_vt1709_6ch(struct hda_codec *codec) { struct via_spec *spec; int err; @@ -2814,66 +2798,444 @@ static int patch_vt1708(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x17; - - /* Add HP and CD pin config connect bit re-config action */ - vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); - vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID); - - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt1709_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration. " + "Using genenic mode...\n"); } - /* add jack detect on/off control */ - if (!via_clone_control(spec, &vt1708_jack_detect_ctl)) - return -ENOMEM; - - /* disable 32bit format on VT1708 */ - if (codec->vendor_id == 0x11061708) - spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback; - - spec->init_verbs[spec->num_iverbs++] = vt1708_init_verbs; - - codec->patch_ops = via_patch_ops; - - INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); - return 0; -} + spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs; -static int patch_vt1709(struct hda_codec *codec) -{ - struct via_spec *spec; - int err; + spec->stream_name_analog = "VT1709 Analog"; + spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; + spec->stream_analog_capture = &vt1709_pcm_analog_capture; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; + spec->stream_name_digital = "VT1709 Digital"; + spec->stream_digital_playback = &vt1709_pcm_digital_playback; + spec->stream_digital_capture = &vt1709_pcm_digital_capture; - spec->aa_mix_nid = 0x18; - err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1709_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1709_capture_mixer; + spec->num_mixers++; } codec->patch_ops = via_patch_ops; + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; +#endif return 0; } -static void set_widgets_power_state_vt1708B(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int imux_is_smixer; - unsigned int parm; - int is_8ch = 0; - if ((spec->codec_type != VT1708B_4CH) && - (codec->vendor_id != 0x11064397)) +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1708B_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb vt1708B_8ch_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output mixers + */ + /* set vol=0 to output mixers */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Setup default input to PW4 */ + {0x1d, AC_VERB_SET_CONNECT_SEL, 0}, + /* PW9 Output enable */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* PW10 Input enable */ + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + { } +}; + +static const struct hda_verb vt1708B_4ch_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output mixers + */ + /* set vol=0 to output mixers */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Setup default input of PW4 to MW0 */ + {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* PW9 Output enable */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* PW10 Input enable */ + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + { } +}; + +static const struct hda_verb vt1708B_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static int via_pcm_open_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + int idle = substream->pstr->substream_opened == 1 + && substream->ref_count == 0; + + analog_low_current_mode(codec, idle); + return 0; +} + +static const struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 8, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 4, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream vt1708B_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x13, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1708B_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream vt1708B_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1708B_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + spec->private_dac_nids[i] = 0x24; + break; + case AUTO_SEQ_SURROUND: + spec->private_dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: + spec->private_dac_nids[i] = 0x25; + break; + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; + hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27}; + hda_nid_t nid, nid_vol = 0; + int i, err; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + + nid_vol = nid_vols[i]; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + + /* add control to PW3 */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + + return 0; +} + +static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */ + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + static const hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} + +static int vt1708B_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + if (spec->autocfg.dig_outs) + spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID; + spec->dig_in_pin = VT1708B_DIGIN_PIN; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = VT1708B_DIGIN_NID; + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + via_hp_build(codec); + + via_smart51_build(spec); + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1708B_loopbacks[] = { + { 0x16, HDA_INPUT, 1 }, + { 0x16, HDA_INPUT, 2 }, + { 0x16, HDA_INPUT, 3 }, + { 0x16, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + +static void set_widgets_power_state_vt1708B(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + int is_8ch = 0; + if ((spec->codec_type != VT1708B_4CH) && + (codec->vendor_id != 0x11064397)) is_8ch = 1; /* SW0 (17h) = stereo mixer */ @@ -2947,107 +3309,61 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) } static int patch_vt1708S(struct hda_codec *codec); -static int patch_vt1708B(struct hda_codec *codec) +static int patch_vt1708B_8ch(struct hda_codec *codec) { struct via_spec *spec; int err; if (get_codec_type(codec) == VT1708BCE) return patch_vt1708S(codec); - /* create a codec specific record */ spec = via_new_spec(codec); if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x16; - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt1708B_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); } - codec->patch_ops = via_patch_ops; - - spec->set_widgets_power_state = set_widgets_power_state_vt1708B; - - return 0; -} - -/* Patch for VT1708S */ -static const struct hda_verb vt1708S_init_verbs[] = { - /* Enable Mic Boost Volume backdoor */ - {0x1, 0xf98, 0x1}, - /* don't bybass mixer */ - {0x1, 0xf88, 0xc0}, - { } -}; + spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs; -/* fill out digital output widgets; one for master and one for slave outputs */ -static void fill_dig_outs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; + spec->stream_name_analog = "VT1708B Analog"; + spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback; + spec->stream_analog_capture = &vt1708B_pcm_analog_capture; - for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t nid; - int conn; + spec->stream_name_digital = "VT1708B Digital"; + spec->stream_digital_playback = &vt1708B_pcm_digital_playback; + spec->stream_digital_capture = &vt1708B_pcm_digital_capture; - nid = spec->autocfg.dig_out_pins[i]; - if (!nid) - continue; - conn = snd_hda_get_connections(codec, nid, &nid, 1); - if (conn < 1) - continue; - if (!spec->multiout.dig_out_nid) - spec->multiout.dig_out_nid = nid; - else { - spec->slave_dig_outs[0] = nid; - break; /* at most two dig outs */ - } + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1708B_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1708B_capture_mixer; + spec->num_mixers++; } -} -static void fill_dig_in(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t dig_nid; - int i, err; + codec->patch_ops = via_patch_ops; - if (!spec->autocfg.dig_in_pin) - return; + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708B_loopbacks; +#endif - dig_nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, dig_nid++) { - unsigned int wcaps = get_wcaps(codec, dig_nid); - if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) - continue; - if (!(wcaps & AC_WCAP_DIGITAL)) - continue; - if (!(wcaps & AC_WCAP_CONN_LIST)) - continue; - err = get_connection_index(codec, dig_nid, - spec->autocfg.dig_in_pin); - if (err >= 0) { - spec->dig_in_nid = dig_nid; - break; - } - } -} + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; -static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin, - int offset, int num_steps, int step_size) -{ - snd_hda_override_amp_caps(codec, pin, HDA_INPUT, - (offset << AC_AMPCAP_OFFSET_SHIFT) | - (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) | - (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) | - (0 << AC_AMPCAP_MUTE_SHIFT)); + return 0; } -static int patch_vt1708S(struct hda_codec *codec) +static int patch_vt1708B_4ch(struct hda_codec *codec) { struct via_spec *spec; int err; @@ -3057,28 +3373,536 @@ static int patch_vt1708S(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x16; - override_mic_boost(codec, 0x1a, 0, 3, 40); - override_mic_boost(codec, 0x1e, 0, 3, 40); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt1708B_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); } - spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs; - codec->patch_ops = via_patch_ops; + spec->stream_name_analog = "VT1708B Analog"; + spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback; + spec->stream_analog_capture = &vt1708B_pcm_analog_capture; - /* correct names for VT1708BCE */ + spec->stream_name_digital = "VT1708B Digital"; + spec->stream_digital_playback = &vt1708B_pcm_digital_playback; + spec->stream_digital_capture = &vt1708B_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1708B_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1708B_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708B_loopbacks; +#endif + + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + + return 0; +} + +/* Patch for VT1708S */ + +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1708S_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt1708S_volume_init_verbs[] = { + /* Unmute ADC0-1 and set the default input to mic-in */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the + * analog-loopback mixer widget */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* Setup default input of PW4 to MW0 */ + {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* PW9, PW10 Output enable */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Enable Mic Boost Volume backdoor */ + {0x1, 0xf98, 0x1}, + /* don't bybass mixer */ + {0x1, 0xf88, 0xc0}, + { } +}; + +static const struct hda_verb vt1708S_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_verb vt1705_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1708S_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 8, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1705_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1708S_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x13, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1708S_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + if (spec->codec->vendor_id == 0x11064397) + spec->private_dac_nids[i] = 0x25; + else + spec->private_dac_nids[i] = 0x24; + break; + case AUTO_SEQ_SURROUND: + spec->private_dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: + spec->private_dac_nids[i] = 0x25; + break; + } + } + } + + /* for Smart 5.1, line/mic inputs double as output pins */ + if (cfg->line_outs == 1) { + spec->multiout.num_dacs = 3; + spec->private_dac_nids[AUTO_SEQ_SURROUND] = 0x11; + if (spec->codec->vendor_id == 0x11064397) + spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x25; + else + spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x24; + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct via_spec *spec = codec->spec; + char name[32]; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; + hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25}, + {0x10, 0x11, 0x25, 0} }; + hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27}, + {0x1C, 0x18, 0x27, 0} }; + hda_nid_t nid, nid_vol, nid_mute; + int i, err; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; + + /* for Smart 5.1, there are always at least six channels */ + if (!nid && i > AUTO_SEQ_CENLFE) + continue; + + if (codec->vendor_id == 0x11064397) { + nid_vol = nid_vols[1][i]; + nid_mute = nid_mutes[1][i]; + } else { + nid_vol = nid_vols[0][i]; + nid_mute = nid_mutes[0][i]; + } + if (!nid_vol && !nid_mute) + continue; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, + 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, + 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + + /* Front */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, + 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, + 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + + return 0; +} + +static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */ + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} + +/* fill out digital output widgets; one for master and one for slave outputs */ +static void fill_dig_outs(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.dig_outs; i++) { + hda_nid_t nid; + int conn; + + nid = spec->autocfg.dig_out_pins[i]; + if (!nid) + continue; + conn = snd_hda_get_connections(codec, nid, &nid, 1); + if (conn < 1) + continue; + if (!spec->multiout.dig_out_nid) + spec->multiout.dig_out_nid = nid; + else { + spec->slave_dig_outs[0] = nid; + break; /* at most two dig outs */ + } + } +} + +static int vt1708S_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + fill_dig_outs(codec); + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + via_hp_build(codec); + + via_smart51_build(spec); + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1708S_loopbacks[] = { + { 0x16, HDA_INPUT, 1 }, + { 0x16, HDA_INPUT, 2 }, + { 0x16, HDA_INPUT, 3 }, + { 0x16, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + +static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin, + int offset, int num_steps, int step_size) +{ + snd_hda_override_amp_caps(codec, pin, HDA_INPUT, + (offset << AC_AMPCAP_OFFSET_SHIFT) | + (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) | + (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT)); +} + +static int patch_vt1708S(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; + + /* automatic parse from the BIOS config */ + err = vt1708S_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; + if (codec->vendor_id == 0x11064397) + spec->init_verbs[spec->num_iverbs++] = + vt1705_uniwill_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt1708S_uniwill_init_verbs; + + if (codec->vendor_id == 0x11060440) + spec->stream_name_analog = "VT1818S Analog"; + else if (codec->vendor_id == 0x11064397) + spec->stream_name_analog = "VT1705 Analog"; + else + spec->stream_name_analog = "VT1708S Analog"; + if (codec->vendor_id == 0x11064397) + spec->stream_analog_playback = &vt1705_pcm_analog_playback; + else + spec->stream_analog_playback = &vt1708S_pcm_analog_playback; + spec->stream_analog_capture = &vt1708S_pcm_analog_capture; + + if (codec->vendor_id == 0x11060440) + spec->stream_name_digital = "VT1818S Digital"; + else if (codec->vendor_id == 0x11064397) + spec->stream_name_digital = "VT1705 Digital"; + else + spec->stream_name_digital = "VT1708S Digital"; + spec->stream_digital_playback = &vt1708S_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1708S_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x1a, 0, 3, 40); + override_mic_boost(codec, 0x1e, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1708S_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708S_loopbacks; +#endif + + /* correct names for VT1708BCE */ if (get_codec_type(codec) == VT1708BCE) { kfree(codec->chip_name); codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL); snprintf(codec->bus->card->mixername, sizeof(codec->bus->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); + spec->stream_name_analog = "VT1708BCE Analog"; + spec->stream_name_digital = "VT1708BCE Digital"; + } + /* correct names for VT1818S */ + if (codec->vendor_id == 0x11060440) { + spec->stream_name_analog = "VT1818S Analog"; + spec->stream_name_digital = "VT1818S Digital"; } /* correct names for VT1705 */ if (codec->vendor_id == 0x11064397) { @@ -3088,19 +3912,263 @@ static int patch_vt1708S(struct hda_codec *codec) sizeof(codec->bus->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); } - spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + return 0; +} + +/* Patch for VT1702 */ + +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1702_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt1702_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */ + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* Setup default input of PW4 to MW0 */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0x1}, + /* PW6 PW7 Output enable */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* mixer enable */ + {0x1, 0xF88, 0x3}, + /* GPIO 0~2 */ + {0x1, 0xF82, 0x3F}, + { } +}; + +static const struct hda_verb vt1702_uniwill_init_verbs[] = { + {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1702_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1702_pcm_analog_capture = { + .substreams = 3, + .channels_min = 2, + .channels_max = 2, + .nid = 0x12, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1702_pcm_digital_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1702_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + + if (cfg->line_out_pins[0]) { + /* config dac list */ + spec->private_dac_nids[0] = 0x10; + } + return 0; } -/* Patch for VT1702 */ +/* add playback controls from the parsed DAC table */ +static int vt1702_auto_create_line_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; -static const struct hda_verb vt1702_init_verbs[] = { - /* mixer enable */ - {0x1, 0xF88, 0x3}, - /* GPIO 0~2 */ - {0x1, 0xF82, 0x3F}, - { } + if (!cfg->line_out_pins[0]) + return -1; + + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + + /* Front */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err, i; + struct hda_input_mux *imux; + static const char * const texts[] = { "ON", "OFF", NULL}; + if (!pin) + return 0; + spec->multiout.hp_nid = 0x1D; + spec->hp_independent_mode_index = 0; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + imux = &spec->private_imux[1]; + + /* for hp mode select */ + for (i = 0; texts[i]; i++) + snd_hda_add_imux_item(imux, texts[i], i, NULL); + + spec->hp_mux = &spec->private_imux[1]; + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + static const hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} + +static int vt1702_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + /* limit AA path volume to 0 dB */ + snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); + err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + fill_dig_outs(codec); + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + via_hp_build(codec); + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1702_loopbacks[] = { + { 0x1A, HDA_INPUT, 1 }, + { 0x1A, HDA_INPUT, 2 }, + { 0x1A, HDA_INPUT, 3 }, + { 0x1A, HDA_INPUT, 4 }, + { } /* end */ }; +#endif static void set_widgets_power_state_vt1702(struct hda_codec *codec) { @@ -3121,62 +4189,414 @@ static void set_widgets_power_state_vt1702(struct hda_codec *codec) snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm); - /* outputs */ - /* PW 3/4 (16h/17h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x17, &parm); - set_pin_power_state(codec, 0x16, &parm); - /* MW0 (1ah), AOW 0/1 (10h/1dh) */ - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); + /* outputs */ + /* PW 3/4 (16h/17h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x17, &parm); + set_pin_power_state(codec, 0x16, &parm); + /* MW0 (1ah), AOW 0/1 (10h/1dh) */ + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); +} + +static int patch_vt1702(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; + + /* automatic parse from the BIOS config */ + err = vt1702_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs; + + spec->stream_name_analog = "VT1702 Analog"; + spec->stream_analog_playback = &vt1702_pcm_analog_playback; + spec->stream_analog_capture = &vt1702_pcm_analog_capture; + + spec->stream_name_digital = "VT1702 Digital"; + spec->stream_digital_playback = &vt1702_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1702_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids); + get_mux_nids(codec); + spec->mixers[spec->num_mixers] = vt1702_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1702_loopbacks; +#endif + + spec->set_widgets_power_state = set_widgets_power_state_vt1702; + return 0; +} + +/* Patch for VT1718S */ + +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1718S_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + .name = "Input Source", + .count = 2, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt1718S_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Enable MW0 adjust Gain 5 */ + {0x1, 0xfb2, 0x10}, + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, + /* PW9 PW10 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + /* PW11 Input enable */ + {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN}, + /* Enable Boost Volume backdoor */ + {0x1, 0xf88, 0x8}, + /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0x2}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0x1}, + { } +}; + + +static const struct hda_verb vt1718S_uniwill_init_verbs[] = { + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1718S_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 10, + .nid = 0x8, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1718S_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1718S_pcm_digital_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream vt1718S_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1718S_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->private_dac_nids[i] = 0x8; + break; + case AUTO_SEQ_CENLFE: + spec->private_dac_nids[i] = 0xa; + break; + case AUTO_SEQ_SURROUND: + spec->private_dac_nids[i] = 0x9; + break; + case AUTO_SEQ_SIDE: + spec->private_dac_nids[i] = 0xb; + break; + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; + hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb}; + hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27}; + hda_nid_t nid, nid_vol, nid_mute = 0; + int i, err; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + nid_vol = nid_vols[i]; + nid_mute = nid_mutes[i]; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x21, 3, 5, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x21, 3, 5, + HDA_INPUT)); + if (err < 0) + return err; + /* Front */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + return 0; +} + +static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0xc; /* AOW4 */ + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; } -static int patch_vt1702(struct hda_codec *codec) +/* create playback/capture controls for input pins */ +static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { - struct via_spec *spec; - int err; + static const hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; +static int vt1718S_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; - spec->aa_mix_nid = 0x1a; + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - /* limit AA path volume to 0 dB */ - snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); + if (err < 0) + return err; + err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); + err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) return err; - } - spec->init_verbs[spec->num_iverbs++] = vt1702_init_verbs; + spec->multiout.max_channels = spec->multiout.num_dacs * 2; - codec->patch_ops = via_patch_ops; + fill_dig_outs(codec); - spec->set_widgets_power_state = set_widgets_power_state_vt1702; - return 0; -} + if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428) + spec->dig_in_nid = 0x13; -/* Patch for VT1718S */ + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; -static const struct hda_verb vt1718S_init_verbs[] = { - /* Enable MW0 adjust Gain 5 */ - {0x1, 0xfb2, 0x10}, - /* Enable Boost Volume backdoor */ - {0x1, 0xf88, 0x8}, + spec->input_mux = &spec->private_imux[0]; - { } + if (spec->hp_mux) + via_hp_build(codec); + + via_smart51_build(spec); + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1718S_loopbacks[] = { + { 0x21, HDA_INPUT, 1 }, + { 0x21, HDA_INPUT, 2 }, + { 0x21, HDA_INPUT, 3 }, + { 0x21, HDA_INPUT, 4 }, + { } /* end */ }; +#endif static void set_widgets_power_state_vt1718S(struct hda_codec *codec) { @@ -3244,41 +4664,6 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) } } -/* Add a connection to the primary DAC from AA-mixer for some codecs - * This isn't listed from the raw info, but the chip has a secret connection. - */ -static int add_secret_dac_path(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i, nums; - hda_nid_t conn[8]; - hda_nid_t nid; - - if (!spec->aa_mix_nid) - return 0; - nums = snd_hda_get_connections(codec, spec->aa_mix_nid, conn, - ARRAY_SIZE(conn) - 1); - for (i = 0; i < nums; i++) { - if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT) - return 0; - } - - /* find the primary DAC and add to the connection list */ - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int caps = get_wcaps(codec, nid); - if (get_wcaps_type(caps) == AC_WID_AUD_OUT && - !(caps & AC_WCAP_DIGITAL)) { - conn[nums++] = nid; - return snd_hda_override_conn_list(codec, - spec->aa_mix_nid, - nums, conn); - } - } - return 0; -} - - static int patch_vt1718S(struct hda_codec *codec) { struct via_spec *spec; @@ -3289,22 +4674,57 @@ static int patch_vt1718S(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; - override_mic_boost(codec, 0x2b, 0, 3, 40); - override_mic_boost(codec, 0x29, 0, 3, 40); - add_secret_dac_path(codec); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt1718S_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); } - spec->init_verbs[spec->num_iverbs++] = vt1718S_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs; + + if (codec->vendor_id == 0x11060441) + spec->stream_name_analog = "VT2020 Analog"; + else if (codec->vendor_id == 0x11064441) + spec->stream_name_analog = "VT1828S Analog"; + else + spec->stream_name_analog = "VT1718S Analog"; + spec->stream_analog_playback = &vt1718S_pcm_analog_playback; + spec->stream_analog_capture = &vt1718S_pcm_analog_capture; + + if (codec->vendor_id == 0x11060441) + spec->stream_name_digital = "VT2020 Digital"; + else if (codec->vendor_id == 0x11064441) + spec->stream_name_digital = "VT1828S Digital"; + else + spec->stream_name_digital = "VT1718S Digital"; + spec->stream_digital_playback = &vt1718S_pcm_digital_playback; + if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441) + spec->stream_digital_capture = &vt1718S_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1718S_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x2b, 0, 3, 40); + override_mic_boost(codec, 0x29, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1718S_capture_mixer; + spec->num_mixers++; + } codec->patch_ops = via_patch_ops; + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1718S_loopbacks; +#endif + spec->set_widgets_power_state = set_widgets_power_state_vt1718S; return 0; @@ -3322,64 +4742,388 @@ static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol, return 0; } -static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + int index = 0; + + index = snd_hda_codec_read(codec, 0x26, 0, + AC_VERB_GET_CONNECT_SEL, 0); + if (index != -1) + *ucontrol->value.integer.value = index; + + return 0; +} + +static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + int index = *ucontrol->value.integer.value; + + snd_hda_codec_write(codec, 0x26, 0, + AC_VERB_SET_CONNECT_SEL, index); + spec->dmic_enabled = index; + set_widgets_power_state(codec); + return 1; +} + +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1716S_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = { + HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Mic Capture Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x26, + .count = 1, + .info = vt1716s_dmic_info, + .get = vt1716s_dmic_get, + .put = vt1716s_dmic_put, + }, + {} /* end */ +}; + + +/* mono-out mixer elements */ +static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { + HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct hda_verb vt1716S_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Stereo Mixer = 5 */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0x5}, + + /* Setup default input of PW4 to MW0 */ + {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, + + /* Setup default input of SW1 as MW0 */ + {0x18, AC_VERB_SET_CONNECT_SEL, 0x1}, + + /* Setup default input of SW4 as AOW0 */ + {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, + + /* PW9 PW10 Output enable */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + + /* Unmute SW1, PW12 */ + {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* PW12 Output enable */ + {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Enable Boost Volume backdoor */ + {0x1, 0xf8a, 0x80}, + /* don't bybass mixer */ + {0x1, 0xf88, 0xc0}, + /* Enable mono output */ + {0x1, 0xf90, 0x08}, + { } +}; + + +static const struct hda_verb vt1716S_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1716S_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1716S_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x13, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1716S_pcm_digital_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1716S_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 3; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->private_dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + spec->private_dac_nids[i] = 0x25; + break; + case AUTO_SEQ_SURROUND: + spec->private_dac_nids[i] = 0x11; + break; + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char * const chname[3] = { + "Front", "Surround", "C/LFE" + }; + hda_nid_t nid_vols[] = {0x10, 0x11, 0x25}; + hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27}; + hda_nid_t nid, nid_vol, nid_mute; + int i, err; + + for (i = 0; i <= AUTO_SEQ_CENLFE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + + nid_vol = nid_vols[i]; + nid_mute = nid_mutes[i]; + + if (i == AUTO_SEQ_CENLFE) { + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + return 0; +} + +static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0x25; /* AOW3 */ + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int index = 0; - - index = snd_hda_codec_read(codec, 0x26, 0, - AC_VERB_GET_CONNECT_SEL, 0); - if (index != -1) - *ucontrol->value.integer.value = index; - - return 0; + static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; + return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, + ARRAY_SIZE(pin_idxs)); } -static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int vt1716S_parse_auto_config(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - int index = *ucontrol->value.integer.value; + int err; - snd_hda_codec_write(codec, 0x26, 0, - AC_VERB_SET_CONNECT_SEL, index); - spec->dmic_enabled = index; - set_widgets_power_state(codec); - return 1; -} + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ -static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = { - HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Mic Capture Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x26, - .count = 1, - .info = vt1716s_dmic_info, - .get = vt1716s_dmic_get, - .put = vt1716s_dmic_put, - }, - {} /* end */ -}; + err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + fill_dig_outs(codec); -/* mono-out mixer elements */ -static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { - HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT), - { } /* end */ -}; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; -static const struct hda_verb vt1716S_init_verbs[] = { - /* Enable Boost Volume backdoor */ - {0x1, 0xf8a, 0x80}, - /* don't bybass mixer */ - {0x1, 0xf88, 0xc0}, - /* Enable mono output */ - {0x1, 0xf90, 0x08}, - { } + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + via_hp_build(codec); + + via_smart51_build(spec); + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1716S_loopbacks[] = { + { 0x16, HDA_INPUT, 1 }, + { 0x16, HDA_INPUT, 2 }, + { 0x16, HDA_INPUT, 3 }, + { 0x16, HDA_INPUT, 4 }, + { } /* end */ }; +#endif static void set_widgets_power_state_vt1716S(struct hda_codec *codec) { @@ -3434,101 +5178,440 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) set_pin_power_state(codec, 0x1a, &parm); snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm); - /* Smart 5.1 PW5(1eh) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1e, &parm); - snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm); + /* Smart 5.1 PW5(1eh) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1e, &parm); + snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Mono out */ + /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ + present = snd_hda_jack_detect(codec, 0x1c); + + if (present) + mono_out = 0; + else { + present = snd_hda_jack_detect(codec, 0x1d); + if (!spec->hp_independent_mode && present) + mono_out = 0; + else + mono_out = 1; + } + parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; + snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW 3/4 (1ch/1dh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1c, &parm); + set_pin_power_state(codec, 0x1d, &parm); + /* HP Independent Mode, power on AOW3 */ + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + + /* force to D0 for internal Speaker */ + /* MW0 (16h), AOW0 (10h) */ + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, + mono_out ? AC_PWRST_D0 : parm); +} + +static int patch_vt1716S(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; + + /* automatic parse from the BIOS config */ + err = vt1716S_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs; + + spec->stream_name_analog = "VT1716S Analog"; + spec->stream_analog_playback = &vt1716S_pcm_analog_playback; + spec->stream_analog_capture = &vt1716S_pcm_analog_capture; + + spec->stream_name_digital = "VT1716S Digital"; + spec->stream_digital_playback = &vt1716S_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1716S_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x1a, 0, 3, 40); + override_mic_boost(codec, 0x1e, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1716S_capture_mixer; + spec->num_mixers++; + } + + spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer; + spec->num_mixers++; + + spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1716S_loopbacks; +#endif + + spec->set_widgets_power_state = set_widgets_power_state_vt1716S; + return 0; +} + +/* for vt2002P */ + +/* capture mixer elements */ +static const struct snd_kcontrol_new vt2002P_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt2002P_volume_init_verbs[] = { + /* Class-D speaker related verbs */ + {0x1, 0xfe0, 0x4}, + {0x1, 0xfe9, 0x80}, + {0x1, 0xfe2, 0x22}, + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + + /* Enable Boost Volume backdoor */ + {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* set MUX0/1/4/8 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x37, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3b, AC_VERB_SET_CONNECT_SEL, 0}, + + /* set PW0 index=0 (MW0) */ + {0x24, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Enable AOW0 to MW9 */ + {0x1, 0xfb8, 0x88}, + { } +}; +static const struct hda_verb vt1802_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + + /* Enable Boost Volume backdoor */ + {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* set MUX0/1/4/8 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x38, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3c, AC_VERB_SET_CONNECT_SEL, 0}, + + /* set PW0 index=0 (MW0) */ + {0x24, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Enable AOW0 to MW9 */ + {0x1, 0xfb8, 0x88}, + { } +}; + + +static const struct hda_verb vt2002P_uniwill_init_verbs[] = { + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; +static const struct hda_verb vt1802_uniwill_init_verbs[] = { + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt2002P_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x8, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt2002P_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt2002P_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt2002P_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + if (cfg->line_out_pins[0]) + spec->private_dac_nids[0] = 0x8; + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; + hda_nid_t sw_nid; + + if (!cfg->line_out_pins[0]) + return -1; + + if (spec->codec_type == VT1802) + sw_nid = 0x28; + else + sw_nid = 0x26; + + /* Line-Out: PortE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0x9; + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL( + spec->multiout.hp_nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; +} - /* Mono out */ - /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ - present = snd_hda_jack_detect(codec, 0x1c); +/* create playback/capture controls for input pins */ +static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct via_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux[0]; + static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff }; + int err; - if (present) - mono_out = 0; - else { - present = snd_hda_jack_detect(codec, 0x1d); - if (!spec->hp_independent_mode && present) - mono_out = 0; - else - mono_out = 1; - } - parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; - snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm); + err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, + ARRAY_SIZE(pin_idxs)); + if (err < 0) + return err; + /* build volume/mute control of loopback */ + err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21); + if (err < 0) + return err; - /* PW 3/4 (1ch/1dh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1c, &parm); - set_pin_power_state(codec, 0x1d, &parm); - /* HP Independent Mode, power on AOW3 */ - if (spec->hp_independent_mode) - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); + /* for digital mic select */ + snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL); - /* force to D0 for internal Speaker */ - /* MW0 (16h), AOW0 (10h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - mono_out ? AC_PWRST_D0 : parm); + return 0; } -static int patch_vt1716S(struct hda_codec *codec) +static int vt2002P_parse_auto_config(struct hda_codec *codec) { - struct via_spec *spec; + struct via_spec *spec = codec->spec; int err; - /* create a codec specific record */ - spec = via_new_spec(codec); - if (spec == NULL) - return -ENOMEM; - spec->aa_mix_nid = 0x16; - override_mic_boost(codec, 0x1a, 0, 3, 40); - override_mic_boost(codec, 0x1e, 0, 3, 40); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); + err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) return err; - } - spec->init_verbs[spec->num_iverbs++] = vt1716S_init_verbs; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ - spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer; - spec->num_mixers++; + err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; - spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; + spec->multiout.max_channels = spec->multiout.num_dacs * 2; - codec->patch_ops = via_patch_ops; + fill_dig_outs(codec); - spec->set_widgets_power_state = set_widgets_power_state_vt1716S; - return 0; -} + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; -/* for vt2002P */ + spec->input_mux = &spec->private_imux[0]; -static const struct hda_verb vt2002P_init_verbs[] = { - /* Class-D speaker related verbs */ - {0x1, 0xfe0, 0x4}, - {0x1, 0xfe9, 0x80}, - {0x1, 0xfe2, 0x22}, - /* Enable Boost Volume backdoor */ - {0x1, 0xfb9, 0x24}, - /* Enable AOW0 to MW9 */ - {0x1, 0xfb8, 0x88}, - { } -}; + if (spec->hp_mux) + via_hp_build(codec); -static const struct hda_verb vt1802_init_verbs[] = { - /* Enable Boost Volume backdoor */ - {0x1, 0xfb9, 0x24}, - /* Enable AOW0 to MW9 */ - {0x1, 0xfb8, 0x88}, - { } + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt2002P_loopbacks[] = { + { 0x21, HDA_INPUT, 0 }, + { 0x21, HDA_INPUT, 1 }, + { 0x21, HDA_INPUT, 2 }, + { } /* end */ }; +#endif static void set_widgets_power_state_vt2002P(struct hda_codec *codec) { @@ -3652,39 +5735,334 @@ static int patch_vt2002P(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; - override_mic_boost(codec, 0x2b, 0, 3, 40); - override_mic_boost(codec, 0x29, 0, 3, 40); - add_secret_dac_path(codec); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt2002P_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); } if (spec->codec_type == VT1802) - spec->init_verbs[spec->num_iverbs++] = vt1802_init_verbs; + spec->init_verbs[spec->num_iverbs++] = + vt1802_volume_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt2002P_volume_init_verbs; + + if (spec->codec_type == VT1802) + spec->init_verbs[spec->num_iverbs++] = + vt1802_uniwill_init_verbs; else - spec->init_verbs[spec->num_iverbs++] = vt2002P_init_verbs; + spec->init_verbs[spec->num_iverbs++] = + vt2002P_uniwill_init_verbs; + + if (spec->codec_type == VT1802) + spec->stream_name_analog = "VT1802 Analog"; + else + spec->stream_name_analog = "VT2002P Analog"; + spec->stream_analog_playback = &vt2002P_pcm_analog_playback; + spec->stream_analog_capture = &vt2002P_pcm_analog_capture; + + if (spec->codec_type == VT1802) + spec->stream_name_digital = "VT1802 Digital"; + else + spec->stream_name_digital = "VT2002P Digital"; + spec->stream_digital_playback = &vt2002P_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt2002P_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x2b, 0, 3, 40); + override_mic_boost(codec, 0x29, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt2002P_capture_mixer; + spec->num_mixers++; + } codec->patch_ops = via_patch_ops; + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt2002P_loopbacks; +#endif + spec->set_widgets_power_state = set_widgets_power_state_vt2002P; return 0; } /* for vt1812 */ -static const struct hda_verb vt1812_init_verbs[] = { +/* capture mixer elements */ +static const struct snd_kcontrol_new vt1812_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + .name = "Input Source", + .count = 2, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static const struct hda_verb vt1812_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + /* Enable Boost Volume backdoor */ {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* set MUX0/1/4/13/15 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x38, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3c, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3d, AC_VERB_SET_CONNECT_SEL, 0}, + /* Enable AOW0 to MW9 */ {0x1, 0xfb8, 0xa8}, { } }; + +static const struct hda_verb vt1812_uniwill_init_verbs[] = { + {0x33, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT }, + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1812_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x8, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1812_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static const struct hda_pcm_stream vt1812_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup + }, +}; +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1812_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + if (cfg->line_out_pins[0]) + spec->private_dac_nids[0] = 0x8; + return 0; +} + + +/* add playback controls from the parsed DAC table */ +static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; + + if (!cfg->line_out_pins[0]) + return -1; + + /* Line-Out: PortE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, + "Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0x9; + spec->hp_independent_mode_index = 1; + + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL( + spec->multiout.hp_nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct via_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux[0]; + static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff }; + int err; + + err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, + ARRAY_SIZE(pin_idxs)); + if (err < 0) + return err; + + /* build volume/mute control of loopback */ + err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21); + if (err < 0) + return err; + + /* for digital mic select */ + snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL); + + return 0; +} + +static int vt1812_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + fill_dig_outs(codec); + err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + + if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs) + return 0; /* can't find valid BIOS pin config */ + + err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + fill_dig_outs(codec); + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + via_hp_build(codec); + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list vt1812_loopbacks[] = { + { 0x21, HDA_INPUT, 0 }, + { 0x21, HDA_INPUT, 1 }, + { 0x21, HDA_INPUT, 2 }, + { } /* end */ +}; +#endif + static void set_widgets_power_state_vt1812(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -3788,22 +6166,47 @@ static int patch_vt1812(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; - override_mic_boost(codec, 0x2b, 0, 3, 40); - override_mic_boost(codec, 0x29, 0, 3, 40); - add_secret_dac_path(codec); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); + err = vt1812_parse_auto_config(codec); if (err < 0) { via_free(codec); return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); } - spec->init_verbs[spec->num_iverbs++] = vt1812_init_verbs; + + spec->init_verbs[spec->num_iverbs++] = vt1812_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs; + + spec->stream_name_analog = "VT1812 Analog"; + spec->stream_analog_playback = &vt1812_pcm_analog_playback; + spec->stream_analog_capture = &vt1812_pcm_analog_capture; + + spec->stream_name_digital = "VT1812 Digital"; + spec->stream_digital_playback = &vt1812_pcm_digital_playback; + + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1812_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x2b, 0, 3, 40); + override_mic_boost(codec, 0x29, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1812_capture_mixer; + spec->num_mixers++; + } codec->patch_ops = via_patch_ops; + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1812_loopbacks; +#endif + spec->set_widgets_power_state = set_widgets_power_state_vt1812; return 0; } @@ -3817,37 +6220,37 @@ static const struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708}, { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708}, { .id = 0x1106e710, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_10ch}, { .id = 0x1106e711, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_10ch}, { .id = 0x1106e712, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_10ch}, { .id = 0x1106e713, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_10ch}, { .id = 0x1106e714, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_6ch}, { .id = 0x1106e715, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_6ch}, { .id = 0x1106e716, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_6ch}, { .id = 0x1106e717, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, + .patch = patch_vt1709_6ch}, { .id = 0x1106e720, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_8ch}, { .id = 0x1106e721, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_8ch}, { .id = 0x1106e722, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_8ch}, { .id = 0x1106e723, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_8ch}, { .id = 0x1106e724, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_4ch}, { .id = 0x1106e725, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_4ch}, { .id = 0x1106e726, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_4ch}, { .id = 0x1106e727, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, + .patch = patch_vt1708B_4ch}, { .id = 0x11060397, .name = "VT1708S", .patch = patch_vt1708S}, { .id = 0x11061397, .name = "VT1708S", diff --git a/trunk/sound/pci/ice1712/ice1712.c b/trunk/sound/pci/ice1712/ice1712.c index be06fb3e45a1..f4594d76b6ea 100644 --- a/trunk/sound/pci/ice1712/ice1712.c +++ b/trunk/sound/pci/ice1712/ice1712.c @@ -2607,7 +2607,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card, ice->profi_port = pci_resource_start(pci, 3); if (request_irq(pci->irq, snd_ice1712_interrupt, IRQF_SHARED, - KBUILD_MODNAME, ice)) { + "ICE1712", ice)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_ice1712_free(ice); return -EIO; @@ -2802,7 +2802,7 @@ static void __devexit snd_ice1712_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ICE1712", .id_table = snd_ice1712_ids, .probe = snd_ice1712_probe, .remove = __devexit_p(snd_ice1712_remove), diff --git a/trunk/sound/pci/ice1712/ice1724.c b/trunk/sound/pci/ice1712/ice1724.c index c2b7f8bc41e4..c1498fa5545f 100644 --- a/trunk/sound/pci/ice1712/ice1724.c +++ b/trunk/sound/pci/ice1712/ice1724.c @@ -2509,7 +2509,7 @@ static int __devinit snd_vt1724_create(struct snd_card *card, ice->profi_port = pci_resource_start(pci, 1); if (request_irq(pci->irq, snd_vt1724_interrupt, - IRQF_SHARED, KBUILD_MODNAME, ice)) { + IRQF_SHARED, "ICE1724", ice)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_vt1724_free(ice); return -EIO; @@ -2802,7 +2802,7 @@ static int snd_vt1724_resume(struct pci_dev *pci) #endif static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "ICE1724", .id_table = snd_vt1724_ids, .probe = snd_vt1724_probe, .remove = __devexit_p(snd_vt1724_remove), diff --git a/trunk/sound/pci/intel8x0.c b/trunk/sound/pci/intel8x0.c index 6a5b387b97fd..6c896dbfd796 100644 --- a/trunk/sound/pci/intel8x0.c +++ b/trunk/sound/pci/intel8x0.c @@ -1882,12 +1882,6 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "Dell Inspiron 6000", .type = AC97_TUNE_HP_MUTE_LED /* cf. Malone #41015 */ }, - { - .subvendor = 0x1028, - .subdevice = 0x0189, - .name = "Dell Inspiron 9300", - .type = AC97_TUNE_HP_MUTE_LED - }, { .subvendor = 0x1028, .subdevice = 0x0191, @@ -2653,7 +2647,7 @@ static int intel8x0_resume(struct pci_dev *pci) pci_set_master(pci); snd_intel8x0_chip_init(chip, 0); if (request_irq(pci->irq, snd_intel8x0_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, card->shortname, chip)) { printk(KERN_ERR "intel8x0: unable to grab IRQ %d, " "disabling device\n", pci->irq); snd_card_disconnect(card); @@ -3112,7 +3106,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, /* request irq after initializaing int_sta_mask, etc */ if (request_irq(pci->irq, snd_intel8x0_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_intel8x0_free(chip); return -EBUSY; @@ -3272,7 +3266,7 @@ static void __devexit snd_intel8x0_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Intel ICH", .id_table = snd_intel8x0_ids, .probe = snd_intel8x0_probe, .remove = __devexit_p(snd_intel8x0_remove), diff --git a/trunk/sound/pci/intel8x0m.c b/trunk/sound/pci/intel8x0m.c index 7c161645d865..f3353b49c785 100644 --- a/trunk/sound/pci/intel8x0m.c +++ b/trunk/sound/pci/intel8x0m.c @@ -1047,7 +1047,7 @@ static int intel8x0m_resume(struct pci_dev *pci) } pci_set_master(pci); if (request_irq(pci->irq, snd_intel8x0m_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + IRQF_SHARED, card->shortname, chip)) { printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, " "disabling device\n", pci->irq); snd_card_disconnect(card); @@ -1174,7 +1174,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card, port_inited: if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_intel8x0m_free(chip); return -EBUSY; @@ -1325,7 +1325,7 @@ static void __devexit snd_intel8x0m_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Intel ICH Modem", .id_table = snd_intel8x0m_ids, .probe = snd_intel8x0m_probe, .remove = __devexit_p(snd_intel8x0m_remove), diff --git a/trunk/sound/pci/korg1212/korg1212.c b/trunk/sound/pci/korg1212/korg1212.c index fc1d573cf306..6d795700be79 100644 --- a/trunk/sound/pci/korg1212/korg1212.c +++ b/trunk/sound/pci/korg1212/korg1212.c @@ -2241,7 +2241,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * err = request_irq(pci->irq, snd_korg1212_interrupt, IRQF_SHARED, - KBUILD_MODNAME, korg1212); + "korg1212", korg1212); if (err) { snd_printk(KERN_ERR "korg1212: unable to grab IRQ %d\n", pci->irq); @@ -2477,7 +2477,7 @@ static void __devexit snd_korg1212_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "korg1212", .id_table = snd_korg1212_ids, .probe = snd_korg1212_probe, .remove = __devexit_p(snd_korg1212_remove), diff --git a/trunk/sound/pci/lola/lola.c b/trunk/sound/pci/lola/lola.c index 3e92e5b5ec3d..2692e5ae5f2d 100644 --- a/trunk/sound/pci/lola/lola.c +++ b/trunk/sound/pci/lola/lola.c @@ -648,7 +648,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, goto errout; if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + DRVNAME, chip)) { printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto errout; @@ -771,7 +771,7 @@ MODULE_DEVICE_TABLE(pci, lola_ids); /* pci_driver definition */ static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = DRVNAME, .id_table = lola_ids, .probe = lola_probe, .remove = __devexit_p(lola_remove), diff --git a/trunk/sound/pci/lola/lola.h b/trunk/sound/pci/lola/lola.h index f0b100059efd..d5708e29b16d 100644 --- a/trunk/sound/pci/lola/lola.h +++ b/trunk/sound/pci/lola/lola.h @@ -480,7 +480,7 @@ struct lola { /* 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_SEPARATION(res) ((res >> 7) & 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); diff --git a/trunk/sound/pci/lola/lola_mixer.c b/trunk/sound/pci/lola/lola_mixer.c index 6b8d64812951..5d518f1a712c 100644 --- a/trunk/sound/pci/lola/lola_mixer.c +++ b/trunk/sound/pci/lola/lola_mixer.c @@ -144,61 +144,40 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid) chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams; chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins; - /* mixer matrix may have unused areas between PhysIn and + /* 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_SEPARATION(val); - - /* example : MixerMatrix of LoLa881 (LoLa16161 uses unused zones) - * +-+ 0-------8------16-------8------16 - * | | | | | | | - * |s| | INPUT | | INPUT | | - * | |->| -> |unused | -> |unused | - * |r| |CAPTURE| | OUTPUT| | - * | | | MIX | | MIX | | - * |c| 8-------------------------------- - * | | | | | | | - * | | | | | | | - * |g| |unused |unused |unused |unused | - * | | | | | | | - * |a| | | | | | - * | | 16------------------------------- - * |i| | | | | | - * | | | PLAYBK| | PLAYBK| | - * |n|->| -> |unused | -> |unused | - * | | |CAPTURE| | OUTPUT| | - * | | | MIX | | MIX | | - * |a| 8-------------------------------- - * |r| | | | | | - * |r| | | | | | - * |a| |unused |unused |unused |unused | - * |y| | | | | | - * | | | | | | | - * +++ 16--|---------------|------------ - * +---V---------------V-----------+ - * | dest_mix_gain_enable array | - * +-------------------------------+ - */ - /* example : MixerMatrix of LoLa280 - * +-+ 0-------8-2 - * | | | | | - * |s| | INPUT | | INPUT - * |r|->| -> | | -> - * |c| |CAPTURE| | <- OUTPUT - * | | | MIX | | MIX - * |g| 8---------- - * |a| | | | - * |i| | PLAYBK| | PLAYBACK - * |n|->| -> | | -> - * | | |CAPTURE| | <- OUTPUT - * |a| | MIX | | MIX - * |r| 8---|----|- - * |r| +---V----V-------------------+ - * |a| | dest_mix_gain_enable array | - * |y| +----------------------------+ + 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) { @@ -213,9 +192,6 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid) (((1U << chip->mixer.dest_phys_outs) - 1) << chip->mixer.dest_phys_out_ofs); - snd_printdd("Mixer src_mask=%x, dest_mask=%x\n", - chip->mixer.src_mask, chip->mixer.dest_mask); - return 0; } @@ -226,19 +202,12 @@ static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id, 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); - /* test if values unchanged */ - if ((val == oldval) && - (gain == readw(&chip->mixer.array->src_gain[id]))) - return 0; - - snd_printdd("lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n", - id, gain, val); - writew(gain, &chip->mixer.array->src_gain[id]); writel(val, &chip->mixer.array->src_gain_enable); lola_codec_flush(chip); /* inform micro-controller about the new source gain */ @@ -300,7 +269,6 @@ static int lola_mixer_set_mapping_gain(struct lola *chip, src, dest); } -#if 0 /* not used */ static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id, unsigned int mask, unsigned short *gains) { @@ -321,7 +289,6 @@ static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id, return lola_codec_write(chip, chip->mixer.nid, LOLA_VERB_SET_DESTINATION_GAIN, id, 0); } -#endif /* not used */ /* */ @@ -409,8 +376,6 @@ static int set_analog_volume(struct lola *chip, int dir, return 0; if (external_call) lola_codec_flush(chip); - snd_printdd("set_analog_volume (dir=%d idx=%d, volume=%d)\n", - dir, idx, val); err = lola_codec_write(chip, pin->nid, LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0); if (err < 0) @@ -462,40 +427,23 @@ static int init_mixer_values(struct lola *chip) { int i; - /* all sample rate converters on */ + /* all src on */ lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false); - /* clear all mixer matrix settings */ + /* clear all matrix */ memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array)); - /* inform firmware about all updated matrix columns - capture part */ - for (i = 0; i < chip->mixer.dest_stream_ins; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_DESTINATION_GAIN, - i, 0); - /* inform firmware about all updated matrix columns - output part */ - 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); - - /* set all digital input source (master) gains to 0dB */ + /* 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 */ - - /* set all digital playback source (master) gains to 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 gain value 0dB diagonally in matrix - part INPUT -> CAPTURE */ + /* 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); } - /* set gain value 0dB diagonally in matrix , part PLAYBACK -> OUTPUT - * (LoLa280 : playback channel 0,2,4,6 linked to output channel 0) - * (LoLa280 : playback channel 1,3,5,7 linked to output channel 1) - */ 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 + @@ -745,7 +693,6 @@ static int __devinit create_src_gain_mixer(struct lola *chip, snd_ctl_new1(&lola_src_gain_mixer, chip)); } -#if 0 /* not used */ /* * destination gain (matrix-like) mixer */ @@ -834,7 +781,6 @@ static int __devinit create_dest_gain_mixer(struct lola *chip, return snd_ctl_add(chip->card, snd_ctl_new1(&lola_dest_gain_mixer, chip)); } -#endif /* not used */ /* */ @@ -852,16 +798,14 @@ int __devinit lola_create_mixer(struct lola *chip) if (err < 0) return err; err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0, - "Digital Capture Volume"); + "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, - "Digital Playback Volume"); + "Stream Source Gain Volume"); if (err < 0) return err; -#if 0 -/* FIXME: buggy mixer matrix handling */ err = create_dest_gain_mixer(chip, chip->mixer.src_phys_ins, 0, chip->mixer.dest_stream_ins, 0, @@ -890,6 +834,6 @@ int __devinit lola_create_mixer(struct lola *chip) "Stream Playback Volume"); if (err < 0) return err; -#endif /* FIXME */ + return init_mixer_values(chip); } diff --git a/trunk/sound/pci/lx6464es/lx6464es.c b/trunk/sound/pci/lx6464es/lx6464es.c index 04ae84b2a107..1bd7a540fd49 100644 --- a/trunk/sound/pci/lx6464es/lx6464es.c +++ b/trunk/sound/pci/lx6464es/lx6464es.c @@ -762,6 +762,7 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran) static int __devinit lx_init_dsp(struct lx6464es *chip) { int err; + u8 mac_address[6]; int i; snd_printdd("->lx_init_dsp\n"); @@ -786,11 +787,11 @@ static int __devinit lx_init_dsp(struct lx6464es *chip) /** \todo the mac address should be ready by not, but it isn't, * so we wait for it */ for (i = 0; i != 1000; ++i) { - err = lx_dsp_get_mac(chip); + err = lx_dsp_get_mac(chip, mac_address); if (err) return err; - if (chip->mac_address[0] || chip->mac_address[1] || chip->mac_address[2] || - chip->mac_address[3] || chip->mac_address[4] || chip->mac_address[5]) + if (mac_address[0] || mac_address[1] || mac_address[2] || + mac_address[3] || mac_address[4] || mac_address[5]) goto mac_ready; msleep(1); } @@ -799,8 +800,8 @@ static int __devinit lx_init_dsp(struct lx6464es *chip) mac_ready: snd_printd(LXP "mac address ready read after: %dms\n", i); snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", - chip->mac_address[0], chip->mac_address[1], chip->mac_address[2], - chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); + mac_address[0], mac_address[1], mac_address[2], + mac_address[3], mac_address[4], mac_address[5]); err = lx_init_get_version_features(chip); if (err) @@ -1030,7 +1031,7 @@ static int __devinit snd_lx6464es_create(struct snd_card *card, chip->port_dsp_bar = pci_ioremap_bar(pci, 2); err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip); + card_name, chip); if (err) { snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq); goto request_irq_failed; @@ -1107,14 +1108,8 @@ static int __devinit snd_lx6464es_probe(struct pci_dev *pci, goto out_free; } - strcpy(card->driver, "LX6464ES"); - sprintf(card->id, "LX6464ES_%02X%02X%02X", - chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); - - sprintf(card->shortname, "LX6464ES %02X.%02X.%02X.%02X.%02X.%02X", - chip->mac_address[0], chip->mac_address[1], chip->mac_address[2], - chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); - + strcpy(card->driver, "lx6464es"); + strcpy(card->shortname, "Digigram LX6464ES"); sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i", card->shortname, chip->port_plx, chip->port_dsp_bar, chip->irq); @@ -1142,7 +1137,7 @@ static void __devexit snd_lx6464es_remove(struct pci_dev *pci) static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Digigram LX6464ES", .id_table = snd_lx6464es_ids, .probe = snd_lx6464es_probe, .remove = __devexit_p(snd_lx6464es_remove), diff --git a/trunk/sound/pci/lx6464es/lx6464es.h b/trunk/sound/pci/lx6464es/lx6464es.h index e2a124ae27e8..aea621eafbb5 100644 --- a/trunk/sound/pci/lx6464es/lx6464es.h +++ b/trunk/sound/pci/lx6464es/lx6464es.h @@ -69,8 +69,6 @@ struct lx6464es { struct pci_dev *pci; int irq; - u8 mac_address[6]; - spinlock_t lock; /* interrupt spinlock */ struct mutex setup_mutex; /* mutex used in hw_params, open * and close */ diff --git a/trunk/sound/pci/lx6464es/lx_core.c b/trunk/sound/pci/lx6464es/lx_core.c index 5c8717e29eeb..617f98b0cbae 100644 --- a/trunk/sound/pci/lx6464es/lx_core.c +++ b/trunk/sound/pci/lx6464es/lx_core.c @@ -424,7 +424,7 @@ int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) return ret; } -int lx_dsp_get_mac(struct lx6464es *chip) +int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address) { u32 macmsb, maclsb; @@ -432,12 +432,12 @@ int lx_dsp_get_mac(struct lx6464es *chip) maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF; /* todo: endianess handling */ - chip->mac_address[5] = ((u8 *)(&maclsb))[0]; - chip->mac_address[4] = ((u8 *)(&maclsb))[1]; - chip->mac_address[3] = ((u8 *)(&maclsb))[2]; - chip->mac_address[2] = ((u8 *)(&macmsb))[0]; - chip->mac_address[1] = ((u8 *)(&macmsb))[1]; - chip->mac_address[0] = ((u8 *)(&macmsb))[2]; + mac_address[5] = ((u8 *)(&maclsb))[0]; + mac_address[4] = ((u8 *)(&maclsb))[1]; + mac_address[3] = ((u8 *)(&maclsb))[2]; + mac_address[2] = ((u8 *)(&macmsb))[0]; + mac_address[1] = ((u8 *)(&macmsb))[1]; + mac_address[0] = ((u8 *)(&macmsb))[2]; return 0; } diff --git a/trunk/sound/pci/lx6464es/lx_core.h b/trunk/sound/pci/lx6464es/lx_core.h index 1dd562980b6c..6bd9cbbbc68d 100644 --- a/trunk/sound/pci/lx6464es/lx_core.h +++ b/trunk/sound/pci/lx6464es/lx_core.h @@ -116,7 +116,7 @@ int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version); int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq); int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran); int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data); -int lx_dsp_get_mac(struct lx6464es *chip); +int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address); /* low-level pipe handling */ diff --git a/trunk/sound/pci/maestro3.c b/trunk/sound/pci/maestro3.c index 0378126e6272..3c40d726b46e 100644 --- a/trunk/sound/pci/maestro3.c +++ b/trunk/sound/pci/maestro3.c @@ -850,10 +850,11 @@ struct snd_m3 { struct input_dev *input_dev; char phys[64]; /* physical device path */ #else + spinlock_t ac97_lock; struct snd_kcontrol *master_switch; struct snd_kcontrol *master_volume; + struct tasklet_struct hwvol_tq; #endif - struct work_struct hwvol_work; unsigned int in_suspend; @@ -1608,10 +1609,13 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s) (without wrap around) in response to volume button presses and then generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 of a byte wide register. The meaning of bits 0 and 4 is unknown. */ -static void snd_m3_update_hw_volume(struct work_struct *work) +static void snd_m3_update_hw_volume(unsigned long private_data) { - struct snd_m3 *chip = container_of(work, struct snd_m3, hwvol_work); + struct snd_m3 *chip = (struct snd_m3 *) private_data; int x, val; +#ifndef CONFIG_SND_MAESTRO3_INPUT + unsigned long flags; +#endif /* Figure out which volume control button was pushed, based on differences from the default register @@ -1641,13 +1645,21 @@ static void snd_m3_update_hw_volume(struct work_struct *work) if (!chip->master_switch || !chip->master_volume) return; - val = snd_ac97_read(chip->ac97, AC97_MASTER); + /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ + spin_lock_irqsave(&chip->ac97_lock, flags); + + val = chip->ac97->regs[AC97_MASTER_VOL]; switch (x) { case 0x88: /* The counters have not changed, yet we've received a HV interrupt. According to tests run by various people this happens when pressing the mute button. */ val ^= 0x8000; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_switch->id); break; case 0xaa: /* counters increased by 1 -> volume up */ @@ -1655,6 +1667,11 @@ static void snd_m3_update_hw_volume(struct work_struct *work) val--; if ((val & 0x7f00) > 0) val -= 0x0100; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); break; case 0x66: /* counters decreased by 1 -> volume down */ @@ -1662,11 +1679,14 @@ static void snd_m3_update_hw_volume(struct work_struct *work) val++; if ((val & 0x7f00) < 0x1f00) val += 0x0100; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); break; } - if (snd_ac97_update(chip->ac97, AC97_MASTER, val)) - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, - &chip->master_switch->id); + spin_unlock_irqrestore(&chip->ac97_lock, flags); #else if (!chip->input_dev) return; @@ -1710,7 +1730,11 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) return IRQ_NONE; if (status & HV_INT_PENDING) - schedule_work(&chip->hwvol_work); +#ifdef CONFIG_SND_MAESTRO3_INPUT + snd_m3_update_hw_volume((unsigned long)chip); +#else + tasklet_schedule(&chip->hwvol_tq); +#endif /* * ack an assp int if its running @@ -1976,14 +2000,24 @@ static unsigned short snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { struct snd_m3 *chip = ac97->private_data; +#ifndef CONFIG_SND_MAESTRO3_INPUT + unsigned long flags; +#endif unsigned short data = 0xffff; if (snd_m3_ac97_wait(chip)) goto fail; +#ifndef CONFIG_SND_MAESTRO3_INPUT + spin_lock_irqsave(&chip->ac97_lock, flags); +#endif snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); if (snd_m3_ac97_wait(chip)) - goto fail; + goto fail_unlock; data = snd_m3_inw(chip, CODEC_DATA); +fail_unlock: +#ifndef CONFIG_SND_MAESTRO3_INPUT + spin_unlock_irqrestore(&chip->ac97_lock, flags); +#endif fail: return data; } @@ -1992,11 +2026,20 @@ static void snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct snd_m3 *chip = ac97->private_data; +#ifndef CONFIG_SND_MAESTRO3_INPUT + unsigned long flags; +#endif if (snd_m3_ac97_wait(chip)) return; +#ifndef CONFIG_SND_MAESTRO3_INPUT + spin_lock_irqsave(&chip->ac97_lock, flags); +#endif snd_m3_outw(chip, val, CODEC_DATA); snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); +#ifndef CONFIG_SND_MAESTRO3_INPUT + spin_unlock_irqrestore(&chip->ac97_lock, flags); +#endif } @@ -2415,7 +2458,6 @@ static int snd_m3_free(struct snd_m3 *chip) struct m3_dma *s; int i; - cancel_work_sync(&chip->hwvol_work); #ifdef CONFIG_SND_MAESTRO3_INPUT if (chip->input_dev) input_unregister_device(chip->input_dev); @@ -2469,7 +2511,6 @@ static int m3_suspend(struct pci_dev *pci, pm_message_t state) return 0; chip->in_suspend = 1; - cancel_work_sync(&chip->hwvol_work); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); @@ -2626,6 +2667,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, } spin_lock_init(&chip->reg_lock); +#ifndef CONFIG_SND_MAESTRO3_INPUT + spin_lock_init(&chip->ac97_lock); +#endif switch (pci->device) { case PCI_DEVICE_ID_ESS_ALLEGRO: @@ -2639,7 +2683,6 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, chip->card = card; chip->pci = pci; chip->irq = -1; - INIT_WORK(&chip->hwvol_work, snd_m3_update_hw_volume); chip->external_amp = enable_amp; if (amp_gpio >= 0 && amp_gpio <= 0x0f) @@ -2709,8 +2752,12 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, snd_m3_hv_init(chip); +#ifndef CONFIG_SND_MAESTRO3_INPUT + tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); +#endif + if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->driver, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_m3_free(chip); return -ENOMEM; @@ -2838,7 +2885,7 @@ static void __devexit snd_m3_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Maestro3", .id_table = snd_m3_ids, .probe = snd_m3_probe, .remove = __devexit_p(snd_m3_remove), diff --git a/trunk/sound/pci/mixart/mixart.c b/trunk/sound/pci/mixart/mixart.c index dbee59906ae1..6c3fd4d1c49d 100644 --- a/trunk/sound/pci/mixart/mixart.c +++ b/trunk/sound/pci/mixart/mixart.c @@ -1268,7 +1268,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, } if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED, - KBUILD_MODNAME, mgr)) { + CARD_NAME, mgr)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_mixart_free(mgr); return -EBUSY; @@ -1381,7 +1381,7 @@ static void __devexit snd_mixart_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Digigram miXart", .id_table = snd_mixart_ids, .probe = snd_mixart_probe, .remove = __devexit_p(snd_mixart_remove), diff --git a/trunk/sound/pci/nm256/nm256.c b/trunk/sound/pci/nm256/nm256.c index 83ea7a7d3eec..5a60492ac7b3 100644 --- a/trunk/sound/pci/nm256/nm256.c +++ b/trunk/sound/pci/nm256/nm256.c @@ -465,7 +465,7 @@ static int snd_nm256_acquire_irq(struct nm256 *chip) mutex_lock(&chip->irq_mutex); if (chip->irq < 0) { if (request_irq(chip->pci->irq, chip->interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + chip->card->driver, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq); mutex_unlock(&chip->irq_mutex); return -EBUSY; @@ -1743,7 +1743,7 @@ static void __devexit snd_nm256_remove(struct pci_dev *pci) static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "NeoMagic 256", .id_table = snd_nm256_ids, .probe = snd_nm256_probe, .remove = __devexit_p(snd_nm256_remove), diff --git a/trunk/sound/pci/oxygen/oxygen.c b/trunk/sound/pci/oxygen/oxygen.c index 218d9854e5cb..d7e8ddd9a67b 100644 --- a/trunk/sound/pci/oxygen/oxygen.c +++ b/trunk/sound/pci/oxygen/oxygen.c @@ -859,7 +859,7 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci, } static struct pci_driver oxygen_driver = { - .name = KBUILD_MODNAME, + .name = "CMI8788", .id_table = oxygen_ids, .probe = generic_oxygen_probe, .remove = __devexit_p(oxygen_pci_remove), diff --git a/trunk/sound/pci/oxygen/oxygen_lib.c b/trunk/sound/pci/oxygen/oxygen_lib.c index 82311fcb86f6..70b739816fcc 100644 --- a/trunk/sound/pci/oxygen/oxygen_lib.c +++ b/trunk/sound/pci/oxygen/oxygen_lib.c @@ -655,7 +655,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, chip->model.init(chip); err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip); + DRIVER, chip); if (err < 0) { snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq); goto err_card; diff --git a/trunk/sound/pci/oxygen/oxygen_pcm.c b/trunk/sound/pci/oxygen/oxygen_pcm.c index cc0bcd9f3350..d5533e34ece9 100644 --- a/trunk/sound/pci/oxygen/oxygen_pcm.c +++ b/trunk/sound/pci/oxygen/oxygen_pcm.c @@ -168,6 +168,12 @@ static int oxygen_open(struct snd_pcm_substream *substream, if (err < 0) return err; } + if (channel == PCM_MULTICH) { + err = snd_pcm_hw_constraint_minmax + (runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 0, 8192000); + if (err < 0) + return err; + } snd_pcm_set_sync(substream); chip->streams[channel] = substream; diff --git a/trunk/sound/pci/oxygen/virtuoso.c b/trunk/sound/pci/oxygen/virtuoso.c index 773db794b43f..469010a8b849 100644 --- a/trunk/sound/pci/oxygen/virtuoso.c +++ b/trunk/sound/pci/oxygen/virtuoso.c @@ -88,7 +88,7 @@ static int __devinit xonar_probe(struct pci_dev *pci, } static struct pci_driver xonar_driver = { - .name = KBUILD_MODNAME, + .name = "AV200", .id_table = xonar_ids, .probe = xonar_probe, .remove = __devexit_p(oxygen_pci_remove), diff --git a/trunk/sound/pci/oxygen/xonar_pcm179x.c b/trunk/sound/pci/oxygen/xonar_pcm179x.c index 32d096c98f5b..54cad38ec30a 100644 --- a/trunk/sound/pci/oxygen/xonar_pcm179x.c +++ b/trunk/sound/pci/oxygen/xonar_pcm179x.c @@ -327,10 +327,8 @@ static void pcm1796_init(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; - data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = + data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD; - if (!data->broken_i2c) - data->pcm1796_regs[0][18 - PCM1796_REG_BASE] |= PCM1796_MUTE; data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = PCM1796_FLT_SHARP | PCM1796_ATS_1; data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = @@ -1125,7 +1123,6 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, chip->model.control_filter = xonar_st_h6_control_filter; chip->model.dac_channels_pcm = 8; chip->model.dac_channels_mixer = 8; - chip->model.dac_volume_min = 255; chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128); break; } diff --git a/trunk/sound/pci/pcxhr/pcxhr.c b/trunk/sound/pci/pcxhr/pcxhr.c index 046578d26f98..95cfde27d25c 100644 --- a/trunk/sound/pci/pcxhr/pcxhr.c +++ b/trunk/sound/pci/pcxhr/pcxhr.c @@ -1501,7 +1501,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, mgr->irq = -1; if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED, - KBUILD_MODNAME, mgr)) { + card_name, mgr)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); pcxhr_free(mgr); return -EBUSY; @@ -1608,7 +1608,7 @@ static void __devexit pcxhr_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Digigram pcxhr", .id_table = pcxhr_ids, .probe = pcxhr_probe, .remove = __devexit_p(pcxhr_remove), diff --git a/trunk/sound/pci/riptide/riptide.c b/trunk/sound/pci/riptide/riptide.c index e34ae14908b3..ad5202efd7a9 100644 --- a/trunk/sound/pci/riptide/riptide.c +++ b/trunk/sound/pci/riptide/riptide.c @@ -1890,7 +1890,7 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci, UNSET_AIE(hwport); if (request_irq(pci->irq, snd_riptide_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "RIPTIDE", chip)) { snd_printk(KERN_ERR "Riptide: unable to grab IRQ %d\n", pci->irq); snd_riptide_free(chip); @@ -2176,7 +2176,7 @@ static void __devexit snd_card_riptide_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RIPTIDE", .id_table = snd_riptide_ids, .probe = snd_card_riptide_probe, .remove = __devexit_p(snd_card_riptide_remove), @@ -2188,7 +2188,7 @@ static struct pci_driver driver = { #ifdef SUPPORT_JOYSTICK static struct pci_driver joystick_driver = { - .name = KBUILD_MODNAME "-joystick", + .name = "Riptide Joystick", .id_table = snd_riptide_joystick_ids, .probe = snd_riptide_joystick_probe, .remove = __devexit_p(snd_riptide_joystick_remove), diff --git a/trunk/sound/pci/rme32.c b/trunk/sound/pci/rme32.c index 6be77a264d47..3c04524de37c 100644 --- a/trunk/sound/pci/rme32.c +++ b/trunk/sound/pci/rme32.c @@ -1355,7 +1355,7 @@ static int __devinit snd_rme32_create(struct rme32 * rme32) } if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_SHARED, - KBUILD_MODNAME, rme32)) { + "RME32", rme32)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); return -EBUSY; } @@ -1985,7 +1985,7 @@ static void __devexit snd_rme32_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RME Digi32", .id_table = snd_rme32_ids, .probe = snd_rme32_probe, .remove = __devexit_p(snd_rme32_remove), diff --git a/trunk/sound/pci/rme96.c b/trunk/sound/pci/rme96.c index 409e5b89519d..9ff247fc8871 100644 --- a/trunk/sound/pci/rme96.c +++ b/trunk/sound/pci/rme96.c @@ -1561,7 +1561,7 @@ snd_rme96_create(struct rme96 *rme96) } if (request_irq(pci->irq, snd_rme96_interrupt, IRQF_SHARED, - KBUILD_MODNAME, rme96)) { + "RME96", rme96)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); return -EBUSY; } @@ -2396,7 +2396,7 @@ static void __devexit snd_rme96_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RME Digi96", .id_table = snd_rme96_ids, .probe = snd_rme96_probe, .remove = __devexit_p(snd_rme96_remove), diff --git a/trunk/sound/pci/rme9652/hdsp.c b/trunk/sound/pci/rme9652/hdsp.c index 1c6d1e1c27c1..2d8332416c83 100644 --- a/trunk/sound/pci/rme9652/hdsp.c +++ b/trunk/sound/pci/rme9652/hdsp.c @@ -5482,7 +5482,7 @@ static int __devinit snd_hdsp_create(struct snd_card *card, } if (request_irq(pci->irq, snd_hdsp_interrupt, IRQF_SHARED, - KBUILD_MODNAME, hdsp)) { + "hdsp", hdsp)) { snd_printk(KERN_ERR "Hammerfall-DSP: unable to use IRQ %d\n", pci->irq); return -EBUSY; } @@ -5637,7 +5637,7 @@ static void __devexit snd_hdsp_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RME Hammerfall DSP", .id_table = snd_hdsp_ids, .probe = snd_hdsp_probe, .remove = __devexit_p(snd_hdsp_remove), diff --git a/trunk/sound/pci/rme9652/hdspm.c b/trunk/sound/pci/rme9652/hdspm.c index af130ee0c45d..c8e402fc3782 100644 --- a/trunk/sound/pci/rme9652/hdspm.c +++ b/trunk/sound/pci/rme9652/hdspm.c @@ -6441,7 +6441,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card, hdspm->port + io_extent - 1); if (request_irq(pci->irq, snd_hdspm_interrupt, - IRQF_SHARED, KBUILD_MODNAME, hdspm)) { + IRQF_SHARED, "hdspm", hdspm)) { snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq); return -EBUSY; } @@ -6779,7 +6779,7 @@ static void __devexit snd_hdspm_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RME Hammerfall DSP MADI", .id_table = snd_hdspm_ids, .probe = snd_hdspm_probe, .remove = __devexit_p(snd_hdspm_remove), diff --git a/trunk/sound/pci/rme9652/rme9652.c b/trunk/sound/pci/rme9652/rme9652.c index 1c7bc1ef8186..c492af5b25f3 100644 --- a/trunk/sound/pci/rme9652/rme9652.c +++ b/trunk/sound/pci/rme9652/rme9652.c @@ -2479,7 +2479,7 @@ static int __devinit snd_rme9652_create(struct snd_card *card, } if (request_irq(pci->irq, snd_rme9652_interrupt, IRQF_SHARED, - KBUILD_MODNAME, rme9652)) { + "rme9652", rme9652)) { snd_printk(KERN_ERR "unable to request IRQ %d\n", pci->irq); return -EBUSY; } @@ -2632,7 +2632,7 @@ static void __devexit snd_rme9652_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "RME Digi9652 (Hammerfall)", .id_table = snd_rme9652_ids, .probe = snd_rme9652_probe, .remove = __devexit_p(snd_rme9652_remove), diff --git a/trunk/sound/pci/sis7019.c b/trunk/sound/pci/sis7019.c index bcf61524a13f..2b5c7a95ae1f 100644 --- a/trunk/sound/pci/sis7019.c +++ b/trunk/sound/pci/sis7019.c @@ -1235,7 +1235,7 @@ static int sis_resume(struct pci_dev *pci) } if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, - KBUILD_MODNAME, sis)) { + card->shortname, sis)) { printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq); goto error; } @@ -1341,7 +1341,7 @@ static int __devinit sis_chip_create(struct snd_card *card, goto error_out_cleanup; if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, - KBUILD_MODNAME, sis)) { + card->shortname, sis)) { printk(KERN_ERR "unable to allocate irq %d\n", sis->irq); goto error_out_cleanup; } @@ -1436,7 +1436,7 @@ static void __devexit snd_sis7019_remove(struct pci_dev *pci) } static struct pci_driver sis7019_driver = { - .name = KBUILD_MODNAME, + .name = "SiS7019", .id_table = snd_sis7019_ids, .probe = snd_sis7019_probe, .remove = __devexit_p(snd_sis7019_remove), diff --git a/trunk/sound/pci/sonicvibes.c b/trunk/sound/pci/sonicvibes.c index 2571a67b389a..337b9facadfd 100644 --- a/trunk/sound/pci/sonicvibes.c +++ b/trunk/sound/pci/sonicvibes.c @@ -1294,7 +1294,7 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card, sonic->game_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_sonicvibes_interrupt, IRQF_SHARED, - KBUILD_MODNAME, sonic)) { + "S3 SonicVibes", sonic)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_sonicvibes_free(sonic); return -EBUSY; @@ -1530,7 +1530,7 @@ static void __devexit snd_sonic_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "S3 SonicVibes", .id_table = snd_sonic_ids, .probe = snd_sonic_probe, .remove = __devexit_p(snd_sonic_remove), diff --git a/trunk/sound/pci/trident/trident.c b/trunk/sound/pci/trident/trident.c index d8a128f6fc02..6d0581841d7a 100644 --- a/trunk/sound/pci/trident/trident.c +++ b/trunk/sound/pci/trident/trident.c @@ -172,7 +172,7 @@ static void __devexit snd_trident_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Trident4DWaveAudio", .id_table = snd_trident_ids, .probe = snd_trident_probe, .remove = __devexit_p(snd_trident_remove), diff --git a/trunk/sound/pci/trident/trident_main.c b/trunk/sound/pci/trident/trident_main.c index 5bd57a7c52d2..2870a4fdc130 100644 --- a/trunk/sound/pci/trident/trident_main.c +++ b/trunk/sound/pci/trident/trident_main.c @@ -3598,7 +3598,7 @@ int __devinit snd_trident_create(struct snd_card *card, trident->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_trident_interrupt, IRQF_SHARED, - KBUILD_MODNAME, trident)) { + "Trident Audio", trident)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_trident_free(trident); return -EBUSY; diff --git a/trunk/sound/pci/via82xx.c b/trunk/sound/pci/via82xx.c index f03fd620a2a0..8c5f8b5a59f0 100644 --- a/trunk/sound/pci/via82xx.c +++ b/trunk/sound/pci/via82xx.c @@ -2377,7 +2377,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card, chip_type == TYPE_VIA8233 ? snd_via8233_interrupt : snd_via686_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->driver, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_via82xx_free(chip); return -EBUSY; @@ -2611,7 +2611,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "VIA 82xx Audio", .id_table = snd_via82xx_ids, .probe = snd_via82xx_probe, .remove = __devexit_p(snd_via82xx_remove), diff --git a/trunk/sound/pci/via82xx_modem.c b/trunk/sound/pci/via82xx_modem.c index a386dd9f6732..f7e8bbbe3953 100644 --- a/trunk/sound/pci/via82xx_modem.c +++ b/trunk/sound/pci/via82xx_modem.c @@ -1129,7 +1129,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card, } chip->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + card->driver, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_via82xx_free(chip); return -EBUSY; @@ -1224,7 +1224,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "VIA 82xx Modem", .id_table = snd_via82xx_modem_ids, .probe = snd_via82xx_probe, .remove = __devexit_p(snd_via82xx_remove), diff --git a/trunk/sound/pci/vx222/vx222.c b/trunk/sound/pci/vx222/vx222.c index 5342d5e1366a..99a9a814be0b 100644 --- a/trunk/sound/pci/vx222/vx222.c +++ b/trunk/sound/pci/vx222/vx222.c @@ -169,7 +169,7 @@ static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci vx->port[i] = pci_resource_start(pci, i + 1); if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + CARD_NAME, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_vx222_free(chip); return -EBUSY; @@ -290,7 +290,7 @@ static int snd_vx222_resume(struct pci_dev *pci) #endif static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Digigram VX222", .id_table = snd_vx222_ids, .probe = snd_vx222_probe, .remove = __devexit_p(snd_vx222_remove), diff --git a/trunk/sound/pci/ymfpci/ymfpci.c b/trunk/sound/pci/ymfpci/ymfpci.c index 511d57653124..80c682113381 100644 --- a/trunk/sound/pci/ymfpci/ymfpci.c +++ b/trunk/sound/pci/ymfpci/ymfpci.c @@ -345,7 +345,7 @@ static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci) } static struct pci_driver driver = { - .name = KBUILD_MODNAME, + .name = "Yamaha DS-1 PCI", .id_table = snd_ymfpci_ids, .probe = snd_card_ymfpci_probe, .remove = __devexit_p(snd_card_ymfpci_remove), diff --git a/trunk/sound/pci/ymfpci/ymfpci_main.c b/trunk/sound/pci/ymfpci/ymfpci_main.c index f3260e658b8a..c94c051ad0c8 100644 --- a/trunk/sound/pci/ymfpci/ymfpci_main.c +++ b/trunk/sound/pci/ymfpci/ymfpci_main.c @@ -2380,7 +2380,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card, return -EBUSY; } if (request_irq(pci->irq, snd_ymfpci_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + "YMFPCI", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_ymfpci_free(chip); return -EBUSY; diff --git a/trunk/sound/pcmcia/pdaudiocf/pdaudiocf.c b/trunk/sound/pcmcia/pdaudiocf/pdaudiocf.c index 66488a7a5706..ce33be0e4e98 100644 --- a/trunk/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/trunk/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -223,7 +223,7 @@ static int pdacf_config(struct pcmcia_device *link) if (ret) goto failed; - ret = pcmcia_request_irq(link, pdacf_interrupt); + ret = pcmcia_request_exclusive_irq(link, pdacf_interrupt); if (ret) goto failed; diff --git a/trunk/sound/pcmcia/vx/vxpocket.c b/trunk/sound/pcmcia/vx/vxpocket.c index 31777d1ea49f..d9ef21d8fa73 100644 --- a/trunk/sound/pcmcia/vx/vxpocket.c +++ b/trunk/sound/pcmcia/vx/vxpocket.c @@ -229,7 +229,7 @@ static int vxpocket_config(struct pcmcia_device *link) if (ret) goto failed; - ret = pcmcia_request_irq(link, snd_vx_irq_handler); + ret = pcmcia_request_exclusive_irq(link, snd_vx_irq_handler); if (ret) goto failed; diff --git a/trunk/sound/soc/Makefile b/trunk/sound/soc/Makefile index 4f913876f332..1ed61c5df2c5 100644 --- a/trunk/sound/soc/Makefile +++ b/trunk/sound/soc/Makefile @@ -1,5 +1,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o -snd-soc-core-objs += soc-pcm.o soc-io.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ diff --git a/trunk/sound/soc/atmel/atmel-pcm.c b/trunk/sound/soc/atmel/atmel-pcm.c index f81d4c3f8956..d0e75323ec19 100644 --- a/trunk/sound/soc/atmel/atmel-pcm.c +++ b/trunk/sound/soc/atmel/atmel-pcm.c @@ -364,11 +364,9 @@ static struct snd_pcm_ops atmel_pcm_ops = { \*--------------------------------------------------------------------------*/ static u64 atmel_pcm_dmamask = 0xffffffff; -static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int atmel_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) @@ -384,7 +382,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) } if (dai->driver->capture.channels_min) { - pr_debug("atmel-pcm:" + pr_debug("at32-pcm:" "Allocating PCM capture DMA buffer\n"); ret = atmel_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); diff --git a/trunk/sound/soc/atmel/atmel-pcm.h b/trunk/sound/soc/atmel/atmel-pcm.h index 5e0a95e64329..2597329302e7 100644 --- a/trunk/sound/soc/atmel/atmel-pcm.h +++ b/trunk/sound/soc/atmel/atmel-pcm.h @@ -60,7 +60,7 @@ struct atmel_ssc_mask { * This structure, shared between the PCM driver and the interface, * contains all information required by the PCM driver to perform the * PDC DMA operation. All fields except dma_intr_handler() are initialized - * by the interface. The dma_intr_handler() pointer is set by the PCM + * by the interface. The dms_intr_handler() pointer is set by the PCM * driver and called by the interface SSC interrupt handler if it is * non-NULL. */ diff --git a/trunk/sound/soc/atmel/atmel_ssc_dai.c b/trunk/sound/soc/atmel/atmel_ssc_dai.c index 71225090c49f..eda955b15834 100644 --- a/trunk/sound/soc/atmel/atmel_ssc_dai.c +++ b/trunk/sound/soc/atmel/atmel_ssc_dai.c @@ -402,7 +402,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S && bits > 16) { printk(KERN_WARNING - "atmel_ssc_dai: sample size %d " + "atmel_ssc_dai: sample size %d" "is too large for I2S\n", bits); return -EINVAL; } @@ -838,8 +838,10 @@ int atmel_ssc_set_audio(int ssc_id) } ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id); - if (!ssc_pdev) + if (!ssc_pdev) { + ssc_free(ssc); return -ENOMEM; + } /* If we can grab the SSC briefly to parent the DAI device off it */ ssc = ssc_request(ssc_id); diff --git a/trunk/sound/soc/atmel/sam9g20_wm8731.c b/trunk/sound/soc/atmel/sam9g20_wm8731.c index bad3aa14d5b3..95572d290c27 100644 --- a/trunk/sound/soc/atmel/sam9g20_wm8731.c +++ b/trunk/sound/soc/atmel/sam9g20_wm8731.c @@ -92,7 +92,6 @@ static struct snd_soc_ops at91sam9g20ek_ops = { }; static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card, - struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { static int mclk_on; diff --git a/trunk/sound/soc/au1x/dbdma2.c b/trunk/sound/soc/au1x/dbdma2.c index 20bb53a837b1..10fdd2854e58 100644 --- a/trunk/sound/soc/au1x/dbdma2.c +++ b/trunk/sound/soc/au1x/dbdma2.c @@ -319,11 +319,10 @@ static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } -static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int au1xpsc_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_pcm *pcm = rtd->pcm; - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1); diff --git a/trunk/sound/soc/blackfin/Kconfig b/trunk/sound/soc/blackfin/Kconfig index fe9d548a6837..ae403597fd31 100644 --- a/trunk/sound/soc/blackfin/Kconfig +++ b/trunk/sound/soc/blackfin/Kconfig @@ -10,35 +10,12 @@ config SND_BF5XX_I2S config SND_BF5XX_SOC_SSM2602 tristate "SoC SSM2602 Audio support for BF52x ezkit" - depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) - select SND_BF5XX_SOC_I2S - select SND_SOC_SSM2602 - help - Say Y if you want to add support for SoC audio on BF527-EZKIT. - -config SND_SOC_BFIN_EVAL_ADAU1701 - tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" depends on SND_BF5XX_I2S select SND_BF5XX_SOC_I2S - select SND_SOC_ADAU1701 + select SND_SOC_SSM2602 select I2C help - Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ - board connected to one of the Blackfin evaluation boards like the - BF5XX-STAMP or BF5XX-EZKIT. - -config SND_SOC_BFIN_EVAL_ADAV80X - tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards" - depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) - select SND_BF5XX_SOC_I2S - select SND_SOC_ADAV80X - help - Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or - EVAL-ADAV803 board connected to one of the Blackfin evaluation boards - like the BF5XX-STAMP or BF5XX-EZKIT. - - Note: This driver assumes that the ADAV80X digital record and playback - interfaces are connected to the first SPORT port on the BF5XX board. + Say Y if you want to add support for SoC audio on BF527-EZKIT. config SND_BF5XX_SOC_AD73311 tristate "SoC AD73311 Audio support for Blackfin" diff --git a/trunk/sound/soc/blackfin/Makefile b/trunk/sound/soc/blackfin/Makefile index 6018bf52a234..49af3f32aec8 100644 --- a/trunk/sound/soc/blackfin/Makefile +++ b/trunk/sound/soc/blackfin/Makefile @@ -21,13 +21,9 @@ snd-ad1980-objs := bf5xx-ad1980.o snd-ssm2602-objs := bf5xx-ssm2602.o snd-ad73311-objs := bf5xx-ad73311.o snd-ad193x-objs := bf5xx-ad193x.o -snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o -snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o -obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o -obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o diff --git a/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c b/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c index 9e59f680bc19..98b44b316e78 100644 --- a/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/trunk/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -418,11 +418,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); -int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd) +int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; pr_debug("%s enter\n", __func__); diff --git a/trunk/sound/soc/blackfin/bf5xx-i2s-pcm.c b/trunk/sound/soc/blackfin/bf5xx-i2s-pcm.c index 61ddf942fd4d..f1fd95bb6416 100644 --- a/trunk/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/trunk/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -168,7 +168,7 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); - ret = snd_pcm_hw_constraint_integer(runtime, + ret = snd_pcm_hw_constraint_integer(runtime, \ SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out; @@ -257,11 +257,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); -int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd) +int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; pr_debug("%s enter\n", __func__); @@ -306,8 +304,8 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev) static struct platform_driver bfin_i2s_pcm_driver = { .driver = { - .name = "bfin-i2s-pcm-audio", - .owner = THIS_MODULE, + .name = "bfin-i2s-pcm-audio", + .owner = THIS_MODULE, }, .probe = bfin_i2s_soc_platform_probe, diff --git a/trunk/sound/soc/blackfin/bf5xx-tdm-pcm.c b/trunk/sound/soc/blackfin/bf5xx-tdm-pcm.c index c95cc03d583d..07cfc7a9e49a 100644 --- a/trunk/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/trunk/sound/soc/blackfin/bf5xx-tdm-pcm.c @@ -283,11 +283,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); -static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd) +static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/blackfin/bfin-eval-adau1701.c b/trunk/sound/soc/blackfin/bfin-eval-adau1701.c deleted file mode 100644 index e5550acba2c2..000000000000 --- a/trunk/sound/soc/blackfin/bfin-eval-adau1701.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Machine driver for EVAL-ADAU1701MINIZ on Analog Devices bfin - * evaluation boards. - * - * Copyright 2011 Analog Devices Inc. - * Author: Lars-Peter Clausen - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include - -#include "../codecs/adau1701.h" - -static const struct snd_soc_dapm_widget bfin_eval_adau1701_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), -}; - -static const struct snd_soc_dapm_route bfin_eval_adau1701_dapm_routes[] = { - { "Speaker", NULL, "OUT0" }, - { "Speaker", NULL, "OUT1" }, - { "Line Out", NULL, "OUT2" }, - { "Line Out", NULL, "OUT3" }, - - { "IN0", NULL, "Line In" }, - { "IN1", NULL, "Line In" }, -}; - -static int bfin_eval_adau1701_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(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret) - return 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) - return ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1701_CLK_SRC_OSC, 12288000, - SND_SOC_CLOCK_IN); - - return ret; -} - -static struct snd_soc_ops bfin_eval_adau1701_ops = { - .hw_params = bfin_eval_adau1701_hw_params, -}; - -static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = { - { - .name = "adau1701", - .stream_name = "adau1701", - .cpu_dai_name = "bfin-i2s.0", - .codec_dai_name = "adau1701", - .platform_name = "bfin-i2s-pcm-audio", - .codec_name = "adau1701.0-0034", - .ops = &bfin_eval_adau1701_ops, - }, - { - .name = "adau1701", - .stream_name = "adau1701", - .cpu_dai_name = "bfin-i2s.1", - .codec_dai_name = "adau1701", - .platform_name = "bfin-i2s-pcm-audio", - .codec_name = "adau1701.0-0034", - .ops = &bfin_eval_adau1701_ops, - }, -}; - -static struct snd_soc_card bfin_eval_adau1701 = { - .name = "bfin-eval-adau1701", - .dai_link = &bfin_eval_adau1701_dai[CONFIG_SND_BF5XX_SPORT_NUM], - .num_links = 1, - - .dapm_widgets = bfin_eval_adau1701_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1701_dapm_widgets), - .dapm_routes = bfin_eval_adau1701_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1701_dapm_routes), -}; - -static int bfin_eval_adau1701_probe(struct platform_device *pdev) -{ - struct snd_soc_card *card = &bfin_eval_adau1701; - - card->dev = &pdev->dev; - - return snd_soc_register_card(&bfin_eval_adau1701); -} - -static int __devexit bfin_eval_adau1701_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 bfin_eval_adau1701_driver = { - .driver = { - .name = "bfin-eval-adau1701", - .owner = THIS_MODULE, - .pm = &snd_soc_pm_ops, - }, - .probe = bfin_eval_adau1701_probe, - .remove = __devexit_p(bfin_eval_adau1701_remove), -}; - -static int __init bfin_eval_adau1701_init(void) -{ - return platform_driver_register(&bfin_eval_adau1701_driver); -} -module_init(bfin_eval_adau1701_init); - -static void __exit bfin_eval_adau1701_exit(void) -{ - platform_driver_unregister(&bfin_eval_adau1701_driver); -} -module_exit(bfin_eval_adau1701_exit); - -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("ALSA SoC bfin ADAU1701 driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:bfin-eval-adau1701"); diff --git a/trunk/sound/soc/blackfin/bfin-eval-adav80x.c b/trunk/sound/soc/blackfin/bfin-eval-adav80x.c deleted file mode 100644 index 8d014d01626e..000000000000 --- a/trunk/sound/soc/blackfin/bfin-eval-adav80x.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Machine driver for EVAL-ADAV801 and EVAL-ADAV803 on Analog Devices bfin - * evaluation boards. - * - * Copyright 2011 Analog Devices Inc. - * Author: Lars-Peter Clausen - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include - -#include "../codecs/adav80x.h" - -static const struct snd_soc_dapm_widget bfin_eval_adav80x_dapm_widgets[] = { - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), -}; - -static const struct snd_soc_dapm_route bfin_eval_adav80x_dapm_routes[] = { - { "Line Out", NULL, "VOUTL" }, - { "Line Out", NULL, "VOUTR" }, - - { "VINL", NULL, "Line In" }, - { "VINR", NULL, "Line In" }, -}; - -static int bfin_eval_adav80x_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(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret) - return 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) - return ret; - - ret = snd_soc_dai_set_pll(codec_dai, ADAV80X_PLL1, ADAV80X_PLL_SRC_XTAL, - 27000000, params_rate(params) * 256); - if (ret) - return ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_PLL1, - params_rate(params) * 256, SND_SOC_CLOCK_IN); - - return ret; -} - -static int bfin_eval_adav80x_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *codec_dai = rtd->codec_dai; - - snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK1, 0, - SND_SOC_CLOCK_OUT); - snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK2, 0, - SND_SOC_CLOCK_OUT); - snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK3, 0, - SND_SOC_CLOCK_OUT); - - snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_XTAL, 2700000, 0); - - return 0; -} - -static struct snd_soc_ops bfin_eval_adav80x_ops = { - .hw_params = bfin_eval_adav80x_hw_params, -}; - -static struct snd_soc_dai_link bfin_eval_adav80x_dais[] = { - { - .name = "adav80x", - .stream_name = "ADAV80x HiFi", - .cpu_dai_name = "bfin-i2s.0", - .codec_dai_name = "adav80x-hifi", - .platform_name = "bfin-i2s-pcm-audio", - .init = bfin_eval_adav80x_codec_init, - .ops = &bfin_eval_adav80x_ops, - }, -}; - -static struct snd_soc_card bfin_eval_adav80x = { - .name = "bfin-eval-adav80x", - .dai_link = bfin_eval_adav80x_dais, - .num_links = ARRAY_SIZE(bfin_eval_adav80x_dais), - - .dapm_widgets = bfin_eval_adav80x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(bfin_eval_adav80x_dapm_widgets), - .dapm_routes = bfin_eval_adav80x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(bfin_eval_adav80x_dapm_routes), -}; - -enum bfin_eval_adav80x_type { - BFIN_EVAL_ADAV801, - BFIN_EVAL_ADAV803, -}; - -static int bfin_eval_adav80x_probe(struct platform_device *pdev) -{ - struct snd_soc_card *card = &bfin_eval_adav80x; - const char *codec_name; - - switch (platform_get_device_id(pdev)->driver_data) { - case BFIN_EVAL_ADAV801: - codec_name = "spi0.1"; - break; - case BFIN_EVAL_ADAV803: - codec_name = "adav803.0-0034"; - break; - default: - return -EINVAL; - } - - bfin_eval_adav80x_dais[0].codec_name = codec_name; - - card->dev = &pdev->dev; - - return snd_soc_register_card(&bfin_eval_adav80x); -} - -static int __devexit bfin_eval_adav80x_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - snd_soc_unregister_card(card); - - return 0; -} - -static const struct platform_device_id bfin_eval_adav80x_ids[] = { - { "bfin-eval-adav801", BFIN_EVAL_ADAV801 }, - { "bfin-eval-adav803", BFIN_EVAL_ADAV803 }, - { }, -}; -MODULE_DEVICE_TABLE(platform, bfin_eval_adav80x_ids); - -static struct platform_driver bfin_eval_adav80x_driver = { - .driver = { - .name = "bfin-eval-adav80x", - .owner = THIS_MODULE, - .pm = &snd_soc_pm_ops, - }, - .probe = bfin_eval_adav80x_probe, - .remove = __devexit_p(bfin_eval_adav80x_remove), - .id_table = bfin_eval_adav80x_ids, -}; - -static int __init bfin_eval_adav80x_init(void) -{ - return platform_driver_register(&bfin_eval_adav80x_driver); -} -module_init(bfin_eval_adav80x_init); - -static void __exit bfin_eval_adav80x_exit(void) -{ - platform_driver_unregister(&bfin_eval_adav80x_driver); -} -module_exit(bfin_eval_adav80x_exit); - -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("ALSA SoC bfin adav80x driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/Kconfig b/trunk/sound/soc/codecs/Kconfig index 36a030f1d1f5..98175a096df2 100644 --- a/trunk/sound/soc/codecs/Kconfig +++ b/trunk/sound/soc/codecs/Kconfig @@ -17,7 +17,6 @@ config SND_SOC_ALL_CODECS 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_ADAV80X select SND_SOC_ADS117X select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C @@ -43,7 +42,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_SN95031 if INTEL_SCU_IPC select SND_SOC_SPDIF select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI - select SND_SOC_STA32X if I2C select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER @@ -73,7 +71,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8770 if SPI_MASTER select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8782 select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C @@ -87,7 +84,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8971 if I2C select SND_SOC_WM8974 if I2C select SND_SOC_WM8978 if I2C - select SND_SOC_WM8983 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8990 if I2C @@ -134,14 +130,7 @@ config SND_SOC_AD1980 config SND_SOC_AD73311 tristate - -config SND_SOC_ADAU1701 - select SIGMA - tristate - -config SND_SOC_ADAV80X - tristate - + config SND_SOC_ADS117X tristate @@ -227,9 +216,6 @@ config SND_SOC_SPDIF config SND_SOC_SSM2602 tristate -config SND_SOC_STA32X - tristate - config SND_SOC_STAC9766 tristate @@ -313,9 +299,6 @@ config SND_SOC_WM8770 config SND_SOC_WM8776 tristate -config SND_SOC_WM8782 - tristate - config SND_SOC_WM8804 tristate @@ -355,9 +338,6 @@ config SND_SOC_WM8974 config SND_SOC_WM8978 tristate -config SND_SOC_WM8983 - tristate - config SND_SOC_WM8985 tristate diff --git a/trunk/sound/soc/codecs/Makefile b/trunk/sound/soc/codecs/Makefile index da9990fb8569..fd8558406ef0 100644 --- a/trunk/sound/soc/codecs/Makefile +++ b/trunk/sound/soc/codecs/Makefile @@ -4,8 +4,6 @@ snd-soc-ad1836-objs := ad1836.o snd-soc-ad193x-objs := ad193x.o snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o -snd-soc-adau1701-objs := adau1701.o -snd-soc-adav80x-objs := adav80x.o snd-soc-ads117x-objs := ads117x.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o @@ -30,7 +28,6 @@ snd-soc-alc5623-objs := alc5623.o snd-soc-sn95031-objs := sn95031.o snd-soc-spdif-objs := spdif_transciever.o snd-soc-ssm2602-objs := ssm2602.o -snd-soc-sta32x-objs := sta32x.o snd-soc-stac9766-objs := stac9766.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o @@ -58,7 +55,6 @@ snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o snd-soc-wm8770-objs := wm8770.o snd-soc-wm8776-objs := wm8776.o -snd-soc-wm8782-objs := wm8782.o snd-soc-wm8804-objs := wm8804.o snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o @@ -72,7 +68,6 @@ snd-soc-wm8962-objs := wm8962.o snd-soc-wm8971-objs := wm8971.o snd-soc-wm8974-objs := wm8974.o snd-soc-wm8978-objs := wm8978.o -snd-soc-wm8983-objs := wm8983.o snd-soc-wm8985-objs := wm8985.o snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o @@ -100,8 +95,6 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o -obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o -obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.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 @@ -127,7 +120,6 @@ obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o -obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o @@ -155,7 +147,6 @@ obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o -obj-$(CONFIG_SND_SOC_WM8782) += snd-soc-wm8782.o 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 @@ -169,7 +160,6 @@ obj-$(CONFIG_SND_SOC_WM8962) += snd-soc-wm8962.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o -obj-$(CONFIG_SND_SOC_WM8983) += snd-soc-wm8983.o obj-$(CONFIG_SND_SOC_WM8985) += snd-soc-wm8985.o obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o diff --git a/trunk/sound/soc/codecs/ad1836.c b/trunk/sound/soc/codecs/ad1836.c index 4e5c5726366b..754c496412bd 100644 --- a/trunk/sound/soc/codecs/ad1836.c +++ b/trunk/sound/soc/codecs/ad1836.c @@ -1,10 +1,19 @@ - /* - * Audio Codec driver supporting: - * AD1835A, AD1836, AD1837A, AD1838A, AD1839A +/* + * File: sound/soc/codecs/ad1836.c + * Author: Barry Song + * + * Created: Aug 04 2009 + * Description: Driver for AD1836 sound chip + * + * Modified: + * Copyright 2009 Analog Devices Inc. * - * Copyright 2009-2011 Analog Devices Inc. + * Bugs: Enter bugs at http://blackfin.uclinux.org/ * - * Licensed under the GPL-2 or later. + * This program is free software; 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 @@ -21,15 +30,10 @@ #include #include "ad1836.h" -enum ad1836_type { - AD1835, - AD1836, - AD1838, -}; - /* codec private data */ struct ad1836_priv { - enum ad1836_type type; + enum snd_soc_control_type control_type; + void *control_data; }; /* @@ -40,60 +44,29 @@ static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"}; static const struct soc_enum ad1836_deemp_enum = SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp); -#define AD1836_DAC_VOLUME(x) \ - SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \ - AD1836_DAC_R_VOL(x), 0, 0x3FF, 0) - -#define AD1836_DAC_SWITCH(x) \ - SOC_DOUBLE("DAC" #x " Playback Switch", AD1836_DAC_CTRL2, \ - AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1) - -#define AD1836_ADC_SWITCH(x) \ - SOC_DOUBLE("ADC" #x " Capture Switch", AD1836_ADC_CTRL2, \ - AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1) - -static const struct snd_kcontrol_new ad183x_dac_controls[] = { - AD1836_DAC_VOLUME(1), - AD1836_DAC_SWITCH(1), - AD1836_DAC_VOLUME(2), - AD1836_DAC_SWITCH(2), - AD1836_DAC_VOLUME(3), - AD1836_DAC_SWITCH(3), - AD1836_DAC_VOLUME(4), - AD1836_DAC_SWITCH(4), -}; - -static const struct snd_soc_dapm_widget ad183x_dac_dapm_widgets[] = { - SND_SOC_DAPM_OUTPUT("DAC1OUT"), - SND_SOC_DAPM_OUTPUT("DAC2OUT"), - SND_SOC_DAPM_OUTPUT("DAC3OUT"), - SND_SOC_DAPM_OUTPUT("DAC4OUT"), -}; - -static const struct snd_soc_dapm_route ad183x_dac_routes[] = { - { "DAC1OUT", NULL, "DAC" }, - { "DAC2OUT", NULL, "DAC" }, - { "DAC3OUT", NULL, "DAC" }, - { "DAC4OUT", NULL, "DAC" }, -}; - -static const struct snd_kcontrol_new ad183x_adc_controls[] = { - AD1836_ADC_SWITCH(1), - AD1836_ADC_SWITCH(2), - AD1836_ADC_SWITCH(3), -}; - -static const struct snd_soc_dapm_widget ad183x_adc_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("ADC1IN"), - SND_SOC_DAPM_INPUT("ADC2IN"), -}; - -static const struct snd_soc_dapm_route ad183x_adc_routes[] = { - { "ADC", NULL, "ADC1IN" }, - { "ADC", NULL, "ADC2IN" }, -}; +static const struct snd_kcontrol_new ad1836_snd_controls[] = { + /* DAC volume control */ + SOC_DOUBLE_R("DAC1 Volume", AD1836_DAC_L1_VOL, + AD1836_DAC_R1_VOL, 0, 0x3FF, 0), + SOC_DOUBLE_R("DAC2 Volume", AD1836_DAC_L2_VOL, + AD1836_DAC_R2_VOL, 0, 0x3FF, 0), + SOC_DOUBLE_R("DAC3 Volume", AD1836_DAC_L3_VOL, + AD1836_DAC_R3_VOL, 0, 0x3FF, 0), + + /* ADC switch control */ + SOC_DOUBLE("ADC1 Switch", AD1836_ADC_CTRL2, AD1836_ADCL1_MUTE, + AD1836_ADCR1_MUTE, 1, 1), + SOC_DOUBLE("ADC2 Switch", AD1836_ADC_CTRL2, AD1836_ADCL2_MUTE, + AD1836_ADCR2_MUTE, 1, 1), + + /* DAC switch control */ + SOC_DOUBLE("DAC1 Switch", AD1836_DAC_CTRL2, AD1836_DACL1_MUTE, + AD1836_DACR1_MUTE, 1, 1), + SOC_DOUBLE("DAC2 Switch", AD1836_DAC_CTRL2, AD1836_DACL2_MUTE, + AD1836_DACR2_MUTE, 1, 1), + SOC_DOUBLE("DAC3 Switch", AD1836_DAC_CTRL2, AD1836_DACL3_MUTE, + AD1836_DACR3_MUTE, 1, 1), -static const struct snd_kcontrol_new ad183x_controls[] = { /* ADC high-pass filter */ SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1, AD1836_ADC_HIGHPASS_FILTER, 1, 0), @@ -102,24 +75,27 @@ static const struct snd_kcontrol_new ad183x_controls[] = { SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum), }; -static const struct snd_soc_dapm_widget ad183x_dapm_widgets[] = { +static const struct snd_soc_dapm_widget ad1836_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1, AD1836_DAC_POWERDOWN, 1), SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1, AD1836_ADC_POWERDOWN, 1, NULL, 0), + SND_SOC_DAPM_OUTPUT("DAC1OUT"), + SND_SOC_DAPM_OUTPUT("DAC2OUT"), + SND_SOC_DAPM_OUTPUT("DAC3OUT"), + SND_SOC_DAPM_INPUT("ADC1IN"), + SND_SOC_DAPM_INPUT("ADC2IN"), }; -static const struct snd_soc_dapm_route ad183x_dapm_routes[] = { +static const struct snd_soc_dapm_route audio_paths[] = { { "DAC", NULL, "ADC_PWR" }, { "ADC", NULL, "ADC_PWR" }, -}; - -static const DECLARE_TLV_DB_SCALE(ad1836_in_tlv, 0, 300, 0); - -static const struct snd_kcontrol_new ad1836_controls[] = { - SOC_DOUBLE_TLV("ADC2 Capture Volume", AD1836_ADC_CTRL1, 3, 0, 4, 0, - ad1836_in_tlv), + { "DAC1OUT", "DAC1 Switch", "DAC" }, + { "DAC2OUT", "DAC2 Switch", "DAC" }, + { "DAC3OUT", "DAC3 Switch", "DAC" }, + { "ADC", "ADC1 Switch", "ADC1IN" }, + { "ADC", "ADC2 Switch", "ADC2IN" }, }; /* @@ -189,69 +165,64 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_dai_ops ad1836_dai_ops = { - .hw_params = ad1836_hw_params, - .set_fmt = ad1836_set_dai_fmt, -}; - -#define AD183X_DAI(_name, num_dacs, num_adcs) \ -{ \ - .name = _name "-hifi", \ - .playback = { \ - .stream_name = "Playback", \ - .channels_min = 2, \ - .channels_max = (num_dacs) * 2, \ - .rates = SNDRV_PCM_RATE_48000, \ - .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \ - }, \ - .capture = { \ - .stream_name = "Capture", \ - .channels_min = 2, \ - .channels_max = (num_adcs) * 2, \ - .rates = SNDRV_PCM_RATE_48000, \ - .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \ - }, \ - .ops = &ad1836_dai_ops, \ -} - -static struct snd_soc_dai_driver ad183x_dais[] = { - [AD1835] = AD183X_DAI("ad1835", 4, 1), - [AD1836] = AD183X_DAI("ad1836", 3, 2), - [AD1838] = AD183X_DAI("ad1838", 3, 1), -}; - #ifdef CONFIG_PM -static int ad1836_suspend(struct snd_soc_codec *codec, pm_message_t state) +static int ad1836_soc_suspend(struct snd_soc_codec *codec, + pm_message_t state) { /* reset clock control mode */ - return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, - AD1836_ADC_SERFMT_MASK, 0); + u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); + adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; + + return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); } -static int ad1836_resume(struct snd_soc_codec *codec) +static int ad1836_soc_resume(struct snd_soc_codec *codec) { /* restore clock control mode */ - return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, - AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX); + u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); + adc_ctrl2 |= AD1836_ADC_AUX; + + return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); } #else -#define ad1836_suspend NULL -#define ad1836_resume NULL +#define ad1836_soc_suspend NULL +#define ad1836_soc_resume NULL #endif +static struct snd_soc_dai_ops ad1836_dai_ops = { + .hw_params = ad1836_hw_params, + .set_fmt = ad1836_set_dai_fmt, +}; + +/* codec DAI instance */ +static struct snd_soc_dai_driver ad1836_dai = { + .name = "ad1836-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 6, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &ad1836_dai_ops, +}; + static int ad1836_probe(struct snd_soc_codec *codec) { struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = &codec->dapm; - int num_dacs, num_adcs; int ret = 0; - int i; - - num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2; - num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2; + codec->control_data = ad1836->control_data; ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); if (ret < 0) { dev_err(codec->dev, "failed to set cache I/O: %d\n", @@ -268,46 +239,21 @@ static int ad1836_probe(struct snd_soc_codec *codec) snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100); /* unmute adc channles, adc aux mode */ snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180); + /* left/right diff:PGA/MUX */ + snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); /* volume */ - for (i = 1; i <= num_dacs; ++i) { - snd_soc_write(codec, AD1836_DAC_L_VOL(i), 0x3FF); - snd_soc_write(codec, AD1836_DAC_R_VOL(i), 0x3FF); - } - - if (ad1836->type == AD1836) { - /* left/right diff:PGA/MUX */ - snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); - ret = snd_soc_add_controls(codec, ad1836_controls, - ARRAY_SIZE(ad1836_controls)); - if (ret) - return ret; - } else { - snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00); - } - - ret = snd_soc_add_controls(codec, ad183x_dac_controls, num_dacs * 2); - if (ret) - return ret; - - ret = snd_soc_add_controls(codec, ad183x_adc_controls, num_adcs); - if (ret) - return ret; - - ret = snd_soc_dapm_new_controls(dapm, ad183x_dac_dapm_widgets, num_dacs); - if (ret) - return ret; - - ret = snd_soc_dapm_new_controls(dapm, ad183x_adc_dapm_widgets, num_adcs); - if (ret) - return ret; - - ret = snd_soc_dapm_add_routes(dapm, ad183x_dac_routes, num_dacs); - if (ret) - return ret; - - ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs); - if (ret) - return ret; + snd_soc_write(codec, AD1836_DAC_L1_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_R1_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_L2_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_R2_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF); + snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF); + + snd_soc_add_controls(codec, ad1836_snd_controls, + ARRAY_SIZE(ad1836_snd_controls)); + snd_soc_dapm_new_controls(dapm, ad1836_dapm_widgets, + ARRAY_SIZE(ad1836_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); return ret; } @@ -316,24 +262,19 @@ static int ad1836_probe(struct snd_soc_codec *codec) static int ad1836_remove(struct snd_soc_codec *codec) { /* reset clock control mode */ - return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, - AD1836_ADC_SERFMT_MASK, 0); + u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); + adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; + + return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); } static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { - .probe = ad1836_probe, - .remove = ad1836_remove, - .suspend = ad1836_suspend, - .resume = ad1836_resume, + .probe = ad1836_probe, + .remove = ad1836_remove, + .suspend = ad1836_soc_suspend, + .resume = ad1836_soc_resume, .reg_cache_size = AD1836_NUM_REGS, .reg_word_size = sizeof(u16), - - .controls = ad183x_controls, - .num_controls = ARRAY_SIZE(ad183x_controls), - .dapm_widgets = ad183x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets), - .dapm_routes = ad183x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes), }; static int __devinit ad1836_spi_probe(struct spi_device *spi) @@ -345,12 +286,12 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi) if (ad1836 == NULL) return -ENOMEM; - ad1836->type = spi_get_device_id(spi)->driver_data; - spi_set_drvdata(spi, ad1836); + ad1836->control_data = spi; + ad1836->control_type = SND_SOC_SPI; ret = snd_soc_register_codec(&spi->dev, - &soc_codec_dev_ad1836, &ad183x_dais[ad1836->type], 1); + &soc_codec_dev_ad1836, &ad1836_dai, 1); if (ret < 0) kfree(ad1836); return ret; @@ -362,29 +303,27 @@ static int __devexit ad1836_spi_remove(struct spi_device *spi) kfree(spi_get_drvdata(spi)); return 0; } -static const struct spi_device_id ad1836_ids[] = { - { "ad1835", AD1835 }, - { "ad1836", AD1836 }, - { "ad1837", AD1835 }, - { "ad1838", AD1838 }, - { "ad1839", AD1838 }, - { }, -}; -MODULE_DEVICE_TABLE(spi, ad1836_ids); static struct spi_driver ad1836_spi_driver = { .driver = { - .name = "ad1836", + .name = "ad1836-codec", .owner = THIS_MODULE, }, .probe = ad1836_spi_probe, .remove = __devexit_p(ad1836_spi_remove), - .id_table = ad1836_ids, }; static int __init ad1836_init(void) { - return spi_register_driver(&ad1836_spi_driver); + int ret; + + ret = spi_register_driver(&ad1836_spi_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register ad1836 SPI driver: %d\n", + ret); + } + + return ret; } module_init(ad1836_init); diff --git a/trunk/sound/soc/codecs/ad1836.h b/trunk/sound/soc/codecs/ad1836.h index 444747f0db26..9d6a3f8f8aaf 100644 --- a/trunk/sound/soc/codecs/ad1836.h +++ b/trunk/sound/soc/codecs/ad1836.h @@ -1,10 +1,19 @@ /* - * Audio Codec driver supporting: - * AD1835A, AD1836, AD1837A, AD1838A, AD1839A + * File: sound/soc/codecs/ad1836.h + * Based on: + * Author: Barry Song * - * Copyright 2009-2011 Analog Devices Inc. + * Created: Aug 04, 2009 + * Description: definitions for AD1836 registers * - * Licensed under the GPL-2 or later. + * Modified: + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. */ #ifndef __AD1836_H__ @@ -12,30 +21,39 @@ #define AD1836_DAC_CTRL1 0 #define AD1836_DAC_POWERDOWN 2 -#define AD1836_DAC_SERFMT_MASK 0xE0 +#define AD1836_DAC_SERFMT_MASK 0xE0 #define AD1836_DAC_SERFMT_PCK256 (0x4 << 5) #define AD1836_DAC_SERFMT_PCK128 (0x5 << 5) #define AD1836_DAC_WORD_LEN_MASK 0x18 #define AD1836_DAC_WORD_LEN_OFFSET 3 #define AD1836_DAC_CTRL2 1 +#define AD1836_DACL1_MUTE 0 +#define AD1836_DACR1_MUTE 1 +#define AD1836_DACL2_MUTE 2 +#define AD1836_DACR2_MUTE 3 +#define AD1836_DACL3_MUTE 4 +#define AD1836_DACR3_MUTE 5 -/* These macros are one-based. So AD183X_MUTE_LEFT(1) will return the mute bit - * for the first ADC/DAC */ -#define AD1836_MUTE_LEFT(x) (((x) * 2) - 2) -#define AD1836_MUTE_RIGHT(x) (((x) * 2) - 1) - -#define AD1836_DAC_L_VOL(x) ((x) * 2) -#define AD1836_DAC_R_VOL(x) (1 + ((x) * 2)) +#define AD1836_DAC_L1_VOL 2 +#define AD1836_DAC_R1_VOL 3 +#define AD1836_DAC_L2_VOL 4 +#define AD1836_DAC_R2_VOL 5 +#define AD1836_DAC_L3_VOL 6 +#define AD1836_DAC_R3_VOL 7 #define AD1836_ADC_CTRL1 12 #define AD1836_ADC_POWERDOWN 7 #define AD1836_ADC_HIGHPASS_FILTER 8 #define AD1836_ADC_CTRL2 13 +#define AD1836_ADCL1_MUTE 0 +#define AD1836_ADCR1_MUTE 1 +#define AD1836_ADCL2_MUTE 2 +#define AD1836_ADCR2_MUTE 3 #define AD1836_ADC_WORD_LEN_MASK 0x30 #define AD1836_ADC_WORD_OFFSET 5 -#define AD1836_ADC_SERFMT_MASK (7 << 6) +#define AD1836_ADC_SERFMT_MASK (7 << 6) #define AD1836_ADC_SERFMT_PCK256 (0x4 << 6) #define AD1836_ADC_SERFMT_PCK128 (0x5 << 6) #define AD1836_ADC_AUX (0x6 << 6) diff --git a/trunk/sound/soc/codecs/adau1701.c b/trunk/sound/soc/codecs/adau1701.c deleted file mode 100644 index 2758d5fc60d6..000000000000 --- a/trunk/sound/soc/codecs/adau1701.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Driver for ADAU1701 SigmaDSP processor - * - * Copyright 2011 Analog Devices Inc. - * Author: Lars-Peter Clausen - * based on an inital version by Cliff Cai - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "adau1701.h" - -#define ADAU1701_DSPCTRL 0x1c -#define ADAU1701_SEROCTL 0x1e -#define ADAU1701_SERICTL 0x1f - -#define ADAU1701_AUXNPOW 0x22 - -#define ADAU1701_OSCIPOW 0x26 -#define ADAU1701_DACSET 0x27 - -#define ADAU1701_NUM_REGS 0x28 - -#define ADAU1701_DSPCTRL_CR (1 << 2) -#define ADAU1701_DSPCTRL_DAM (1 << 3) -#define ADAU1701_DSPCTRL_ADM (1 << 4) -#define ADAU1701_DSPCTRL_SR_48 0x00 -#define ADAU1701_DSPCTRL_SR_96 0x01 -#define ADAU1701_DSPCTRL_SR_192 0x02 -#define ADAU1701_DSPCTRL_SR_MASK 0x03 - -#define ADAU1701_SEROCTL_INV_LRCLK 0x2000 -#define ADAU1701_SEROCTL_INV_BCLK 0x1000 -#define ADAU1701_SEROCTL_MASTER 0x0800 - -#define ADAU1701_SEROCTL_OBF16 0x0000 -#define ADAU1701_SEROCTL_OBF8 0x0200 -#define ADAU1701_SEROCTL_OBF4 0x0400 -#define ADAU1701_SEROCTL_OBF2 0x0600 -#define ADAU1701_SEROCTL_OBF_MASK 0x0600 - -#define ADAU1701_SEROCTL_OLF1024 0x0000 -#define ADAU1701_SEROCTL_OLF512 0x0080 -#define ADAU1701_SEROCTL_OLF256 0x0100 -#define ADAU1701_SEROCTL_OLF_MASK 0x0180 - -#define ADAU1701_SEROCTL_MSB_DEALY1 0x0000 -#define ADAU1701_SEROCTL_MSB_DEALY0 0x0004 -#define ADAU1701_SEROCTL_MSB_DEALY8 0x0008 -#define ADAU1701_SEROCTL_MSB_DEALY12 0x000c -#define ADAU1701_SEROCTL_MSB_DEALY16 0x0010 -#define ADAU1701_SEROCTL_MSB_DEALY_MASK 0x001c - -#define ADAU1701_SEROCTL_WORD_LEN_24 0x0000 -#define ADAU1701_SEROCTL_WORD_LEN_20 0x0001 -#define ADAU1701_SEROCTL_WORD_LEN_16 0x0010 -#define ADAU1701_SEROCTL_WORD_LEN_MASK 0x0003 - -#define ADAU1701_AUXNPOW_VBPD 0x40 -#define ADAU1701_AUXNPOW_VRPD 0x20 - -#define ADAU1701_SERICTL_I2S 0 -#define ADAU1701_SERICTL_LEFTJ 1 -#define ADAU1701_SERICTL_TDM 2 -#define ADAU1701_SERICTL_RIGHTJ_24 3 -#define ADAU1701_SERICTL_RIGHTJ_20 4 -#define ADAU1701_SERICTL_RIGHTJ_18 5 -#define ADAU1701_SERICTL_RIGHTJ_16 6 -#define ADAU1701_SERICTL_MODE_MASK 7 -#define ADAU1701_SERICTL_INV_BCLK BIT(3) -#define ADAU1701_SERICTL_INV_LRCLK BIT(4) - -#define ADAU1701_OSCIPOW_OPD 0x04 -#define ADAU1701_DACSET_DACINIT 1 - -#define ADAU1701_FIRMWARE "adau1701.bin" - -struct adau1701 { - unsigned int dai_fmt; -}; - -static const struct snd_kcontrol_new adau1701_controls[] = { - SOC_SINGLE("Master Capture Switch", ADAU1701_DSPCTRL, 4, 1, 0), -}; - -static const struct snd_soc_dapm_widget adau1701_dapm_widgets[] = { - SND_SOC_DAPM_DAC("DAC0", "Playback", ADAU1701_AUXNPOW, 3, 1), - SND_SOC_DAPM_DAC("DAC1", "Playback", ADAU1701_AUXNPOW, 2, 1), - SND_SOC_DAPM_DAC("DAC2", "Playback", ADAU1701_AUXNPOW, 1, 1), - SND_SOC_DAPM_DAC("DAC3", "Playback", ADAU1701_AUXNPOW, 0, 1), - SND_SOC_DAPM_ADC("ADC", "Capture", ADAU1701_AUXNPOW, 7, 1), - - SND_SOC_DAPM_OUTPUT("OUT0"), - SND_SOC_DAPM_OUTPUT("OUT1"), - SND_SOC_DAPM_OUTPUT("OUT2"), - SND_SOC_DAPM_OUTPUT("OUT3"), - SND_SOC_DAPM_INPUT("IN0"), - SND_SOC_DAPM_INPUT("IN1"), -}; - -static const struct snd_soc_dapm_route adau1701_dapm_routes[] = { - { "OUT0", NULL, "DAC0" }, - { "OUT1", NULL, "DAC1" }, - { "OUT2", NULL, "DAC2" }, - { "OUT3", NULL, "DAC3" }, - - { "ADC", NULL, "IN0" }, - { "ADC", NULL, "IN1" }, -}; - -static unsigned int adau1701_register_size(struct snd_soc_codec *codec, - unsigned int reg) -{ - switch (reg) { - case ADAU1701_DSPCTRL: - case ADAU1701_SEROCTL: - case ADAU1701_AUXNPOW: - case ADAU1701_OSCIPOW: - case ADAU1701_DACSET: - return 2; - case ADAU1701_SERICTL: - return 1; - } - - dev_err(codec->dev, "Unsupported register address: %d\n", reg); - return 0; -} - -static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - unsigned int i; - unsigned int size; - uint8_t buf[4]; - int ret; - - size = adau1701_register_size(codec, reg); - if (size == 0) - return -EINVAL; - - snd_soc_cache_write(codec, reg, value); - - buf[0] = 0x08; - buf[1] = reg; - - for (i = size + 1; i >= 2; --i) { - buf[i] = value; - value >>= 8; - } - - ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2); - if (ret == size + 2) - return 0; - else if (ret < 0) - return ret; - else - return -EIO; -} - -static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg) -{ - unsigned int value; - unsigned int ret; - - ret = snd_soc_cache_read(codec, reg, &value); - if (ret) - return ret; - - return value; -} - -static int adau1701_load_firmware(struct snd_soc_codec *codec) -{ - return process_sigma_firmware(codec->control_data, ADAU1701_FIRMWARE); -} - -static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec, - snd_pcm_format_t format) -{ - struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); - unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK; - unsigned int val; - - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: - val = ADAU1701_SEROCTL_WORD_LEN_16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - val = ADAU1701_SEROCTL_WORD_LEN_20; - break; - case SNDRV_PCM_FORMAT_S24_LE: - val = ADAU1701_SEROCTL_WORD_LEN_24; - break; - default: - return -EINVAL; - } - - if (adau1701->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) { - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: - val |= ADAU1701_SEROCTL_MSB_DEALY16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - val |= ADAU1701_SEROCTL_MSB_DEALY12; - break; - case SNDRV_PCM_FORMAT_S24_LE: - val |= ADAU1701_SEROCTL_MSB_DEALY8; - break; - } - mask |= ADAU1701_SEROCTL_MSB_DEALY_MASK; - } - - snd_soc_update_bits(codec, ADAU1701_SEROCTL, mask, val); - - return 0; -} - -static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec, - snd_pcm_format_t format) -{ - struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) - return 0; - - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: - val = ADAU1701_SERICTL_RIGHTJ_16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - val = ADAU1701_SERICTL_RIGHTJ_20; - break; - case SNDRV_PCM_FORMAT_S24_LE: - val = ADAU1701_SERICTL_RIGHTJ_24; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ADAU1701_SERICTL, - ADAU1701_SERICTL_MODE_MASK, val); - - return 0; -} - -static int adau1701_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; - snd_pcm_format_t format; - unsigned int val; - - switch (params_rate(params)) { - case 192000: - val = ADAU1701_DSPCTRL_SR_192; - break; - case 96000: - val = ADAU1701_DSPCTRL_SR_96; - break; - case 48000: - val = ADAU1701_DSPCTRL_SR_48; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ADAU1701_DSPCTRL, - ADAU1701_DSPCTRL_SR_MASK, val); - - format = params_format(params); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return adau1701_set_playback_pcm_format(codec, format); - else - return adau1701_set_capture_pcm_format(codec, format); -} - -static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); - unsigned int serictl = 0x00, seroctl = 0x00; - bool invert_lrclk; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - /* master, 64-bits per sample, 1 frame per sample */ - seroctl |= ADAU1701_SEROCTL_MASTER | ADAU1701_SEROCTL_OBF16 - | ADAU1701_SEROCTL_OLF1024; - break; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - /* clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - invert_lrclk = false; - break; - case SND_SOC_DAIFMT_NB_IF: - invert_lrclk = true; - break; - case SND_SOC_DAIFMT_IB_NF: - invert_lrclk = false; - serictl |= ADAU1701_SERICTL_INV_BCLK; - seroctl |= ADAU1701_SEROCTL_INV_BCLK; - break; - case SND_SOC_DAIFMT_IB_IF: - invert_lrclk = true; - serictl |= ADAU1701_SERICTL_INV_BCLK; - seroctl |= ADAU1701_SEROCTL_INV_BCLK; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - break; - case SND_SOC_DAIFMT_LEFT_J: - serictl |= ADAU1701_SERICTL_LEFTJ; - seroctl |= ADAU1701_SEROCTL_MSB_DEALY0; - invert_lrclk = !invert_lrclk; - break; - case SND_SOC_DAIFMT_RIGHT_J: - serictl |= ADAU1701_SERICTL_RIGHTJ_24; - seroctl |= ADAU1701_SEROCTL_MSB_DEALY8; - invert_lrclk = !invert_lrclk; - break; - default: - return -EINVAL; - } - - if (invert_lrclk) { - seroctl |= ADAU1701_SEROCTL_INV_LRCLK; - serictl |= ADAU1701_SERICTL_INV_LRCLK; - } - - adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; - - snd_soc_write(codec, ADAU1701_SERICTL, serictl); - snd_soc_update_bits(codec, ADAU1701_SEROCTL, - ~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl); - - return 0; -} - -static int adau1701_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - unsigned int mask = ADAU1701_AUXNPOW_VBPD | ADAU1701_AUXNPOW_VRPD; - - switch (level) { - case SND_SOC_BIAS_ON: - break; - case SND_SOC_BIAS_PREPARE: - break; - case SND_SOC_BIAS_STANDBY: - /* Enable VREF and VREF buffer */ - snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, 0x00); - break; - case SND_SOC_BIAS_OFF: - /* Disable VREF and VREF buffer */ - snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, mask); - break; - } - - codec->dapm.bias_level = level; - return 0; -} - -static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - unsigned int mask = ADAU1701_DSPCTRL_DAM; - unsigned int val; - - if (mute) - val = 0; - else - val = mask; - - snd_soc_update_bits(codec, ADAU1701_DSPCTRL, mask, val); - - return 0; -} - -static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, - unsigned int freq, int dir) -{ - unsigned int val; - - switch (clk_id) { - case ADAU1701_CLK_SRC_OSC: - val = 0x0; - break; - case ADAU1701_CLK_SRC_MCLK: - val = ADAU1701_OSCIPOW_OPD; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val); - - return 0; -} - -#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ - SNDRV_PCM_RATE_192000) - -#define ADAU1701_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE) - -static const struct snd_soc_dai_ops adau1701_dai_ops = { - .set_fmt = adau1701_set_dai_fmt, - .hw_params = adau1701_hw_params, - .digital_mute = adau1701_digital_mute, -}; - -static struct snd_soc_dai_driver adau1701_dai = { - .name = "adau1701", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 8, - .rates = ADAU1701_RATES, - .formats = ADAU1701_FORMATS, - }, - .capture = { - .stream_name = "Capture", - .channels_min = 2, - .channels_max = 8, - .rates = ADAU1701_RATES, - .formats = ADAU1701_FORMATS, - }, - .ops = &adau1701_dai_ops, - .symmetric_rates = 1, -}; - -static int adau1701_probe(struct snd_soc_codec *codec) -{ - int ret; - - codec->dapm.idle_bias_off = 1; - - ret = adau1701_load_firmware(codec); - if (ret) - dev_warn(codec->dev, "Failed to load firmware\n"); - - snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); - snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR); - - return 0; -} - -static struct snd_soc_codec_driver adau1701_codec_drv = { - .probe = adau1701_probe, - .set_bias_level = adau1701_set_bias_level, - - .reg_cache_size = ADAU1701_NUM_REGS, - .reg_word_size = sizeof(u16), - - .controls = adau1701_controls, - .num_controls = ARRAY_SIZE(adau1701_controls), - .dapm_widgets = adau1701_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(adau1701_dapm_widgets), - .dapm_routes = adau1701_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes), - - .write = adau1701_write, - .read = adau1701_read, - - .set_sysclk = adau1701_set_sysclk, -}; - -static __devinit int adau1701_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct adau1701 *adau1701; - int ret; - - adau1701 = kzalloc(sizeof(*adau1701), GFP_KERNEL); - if (!adau1701) - return -ENOMEM; - - i2c_set_clientdata(client, adau1701); - ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, - &adau1701_dai, 1); - if (ret < 0) - kfree(adau1701); - - return ret; -} - -static __devexit int adau1701_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 adau1701_i2c_id[] = { - { "adau1701", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id); - -static struct i2c_driver adau1701_i2c_driver = { - .driver = { - .name = "adau1701", - .owner = THIS_MODULE, - }, - .probe = adau1701_i2c_probe, - .remove = __devexit_p(adau1701_i2c_remove), - .id_table = adau1701_i2c_id, -}; - -static int __init adau1701_init(void) -{ - return i2c_add_driver(&adau1701_i2c_driver); -} -module_init(adau1701_init); - -static void __exit adau1701_exit(void) -{ - i2c_del_driver(&adau1701_i2c_driver); -} -module_exit(adau1701_exit); - -MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver"); -MODULE_AUTHOR("Cliff Cai "); -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/adau1701.h b/trunk/sound/soc/codecs/adau1701.h deleted file mode 100644 index 8d0949a2aec9..000000000000 --- a/trunk/sound/soc/codecs/adau1701.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * header file for ADAU1701 SigmaDSP processor - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _ADAU1701_H -#define _ADAU1701_H - -enum adau1701_clk_src { - ADAU1701_CLK_SRC_OSC, - ADAU1701_CLK_SRC_MCLK, -}; - -#endif diff --git a/trunk/sound/soc/codecs/adav80x.c b/trunk/sound/soc/codecs/adav80x.c deleted file mode 100644 index 300c04b70e71..000000000000 --- a/trunk/sound/soc/codecs/adav80x.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * ADAV80X Audio Codec driver supporting ADAV801, ADAV803 - * - * Copyright 2011 Analog Devices Inc. - * Author: Yi Li - * Author: Lars-Peter Clausen - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "adav80x.h" - -#define ADAV80X_PLAYBACK_CTRL 0x04 -#define ADAV80X_AUX_IN_CTRL 0x05 -#define ADAV80X_REC_CTRL 0x06 -#define ADAV80X_AUX_OUT_CTRL 0x07 -#define ADAV80X_DPATH_CTRL1 0x62 -#define ADAV80X_DPATH_CTRL2 0x63 -#define ADAV80X_DAC_CTRL1 0x64 -#define ADAV80X_DAC_CTRL2 0x65 -#define ADAV80X_DAC_CTRL3 0x66 -#define ADAV80X_DAC_L_VOL 0x68 -#define ADAV80X_DAC_R_VOL 0x69 -#define ADAV80X_PGA_L_VOL 0x6c -#define ADAV80X_PGA_R_VOL 0x6d -#define ADAV80X_ADC_CTRL1 0x6e -#define ADAV80X_ADC_CTRL2 0x6f -#define ADAV80X_ADC_L_VOL 0x70 -#define ADAV80X_ADC_R_VOL 0x71 -#define ADAV80X_PLL_CTRL1 0x74 -#define ADAV80X_PLL_CTRL2 0x75 -#define ADAV80X_ICLK_CTRL1 0x76 -#define ADAV80X_ICLK_CTRL2 0x77 -#define ADAV80X_PLL_CLK_SRC 0x78 -#define ADAV80X_PLL_OUTE 0x7a - -#define ADAV80X_PLL_CLK_SRC_PLL_XIN(pll) 0x00 -#define ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll) (0x40 << (pll)) -#define ADAV80X_PLL_CLK_SRC_PLL_MASK(pll) (0x40 << (pll)) - -#define ADAV80X_ICLK_CTRL1_DAC_SRC(src) ((src) << 5) -#define ADAV80X_ICLK_CTRL1_ADC_SRC(src) ((src) << 2) -#define ADAV80X_ICLK_CTRL1_ICLK2_SRC(src) (src) -#define ADAV80X_ICLK_CTRL2_ICLK1_SRC(src) ((src) << 3) - -#define ADAV80X_PLL_CTRL1_PLLDIV 0x10 -#define ADAV80X_PLL_CTRL1_PLLPD(pll) (0x04 << (pll)) -#define ADAV80X_PLL_CTRL1_XTLPD 0x02 - -#define ADAV80X_PLL_CTRL2_FIELD(pll, x) ((x) << ((pll) * 4)) - -#define ADAV80X_PLL_CTRL2_FS_48(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x00) -#define ADAV80X_PLL_CTRL2_FS_32(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x08) -#define ADAV80X_PLL_CTRL2_FS_44(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0c) - -#define ADAV80X_PLL_CTRL2_SEL(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x02) -#define ADAV80X_PLL_CTRL2_DOUB(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x01) -#define ADAV80X_PLL_CTRL2_PLL_MASK(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0f) - -#define ADAV80X_ADC_CTRL1_MODULATOR_MASK 0x80 -#define ADAV80X_ADC_CTRL1_MODULATOR_128FS 0x00 -#define ADAV80X_ADC_CTRL1_MODULATOR_64FS 0x80 - -#define ADAV80X_DAC_CTRL1_PD 0x80 - -#define ADAV80X_DAC_CTRL2_DIV1 0x00 -#define ADAV80X_DAC_CTRL2_DIV1_5 0x10 -#define ADAV80X_DAC_CTRL2_DIV2 0x20 -#define ADAV80X_DAC_CTRL2_DIV3 0x30 -#define ADAV80X_DAC_CTRL2_DIV_MASK 0x30 - -#define ADAV80X_DAC_CTRL2_INTERPOL_256FS 0x00 -#define ADAV80X_DAC_CTRL2_INTERPOL_128FS 0x40 -#define ADAV80X_DAC_CTRL2_INTERPOL_64FS 0x80 -#define ADAV80X_DAC_CTRL2_INTERPOL_MASK 0xc0 - -#define ADAV80X_DAC_CTRL2_DEEMPH_NONE 0x00 -#define ADAV80X_DAC_CTRL2_DEEMPH_44 0x01 -#define ADAV80X_DAC_CTRL2_DEEMPH_32 0x02 -#define ADAV80X_DAC_CTRL2_DEEMPH_48 0x03 -#define ADAV80X_DAC_CTRL2_DEEMPH_MASK 0x01 - -#define ADAV80X_CAPTURE_MODE_MASTER 0x20 -#define ADAV80X_CAPTURE_WORD_LEN24 0x00 -#define ADAV80X_CAPTURE_WORD_LEN20 0x04 -#define ADAV80X_CAPTRUE_WORD_LEN18 0x08 -#define ADAV80X_CAPTURE_WORD_LEN16 0x0c -#define ADAV80X_CAPTURE_WORD_LEN_MASK 0x0c - -#define ADAV80X_CAPTURE_MODE_LEFT_J 0x00 -#define ADAV80X_CAPTURE_MODE_I2S 0x01 -#define ADAV80X_CAPTURE_MODE_RIGHT_J 0x03 -#define ADAV80X_CAPTURE_MODE_MASK 0x03 - -#define ADAV80X_PLAYBACK_MODE_MASTER 0x10 -#define ADAV80X_PLAYBACK_MODE_LEFT_J 0x00 -#define ADAV80X_PLAYBACK_MODE_I2S 0x01 -#define ADAV80X_PLAYBACK_MODE_RIGHT_J_24 0x04 -#define ADAV80X_PLAYBACK_MODE_RIGHT_J_20 0x05 -#define ADAV80X_PLAYBACK_MODE_RIGHT_J_18 0x06 -#define ADAV80X_PLAYBACK_MODE_RIGHT_J_16 0x07 -#define ADAV80X_PLAYBACK_MODE_MASK 0x07 - -#define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x)) - -static u8 adav80x_default_regs[] = { - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x80, 0x26, 0x00, 0x00, - 0x02, 0x40, 0x20, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x92, 0xb1, 0x37, - 0x48, 0xd2, 0xfb, 0xca, 0xd2, 0x15, 0xe8, 0x29, 0xb9, 0x6a, 0xda, 0x2b, - 0xb7, 0xc0, 0x11, 0x65, 0x5c, 0xf6, 0xff, 0x8d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, - 0x00, 0xe8, 0x46, 0xe1, 0x5b, 0xd3, 0x43, 0x77, 0x93, 0xa7, 0x44, 0xee, - 0x32, 0x12, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x3f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, -}; - -struct adav80x { - enum snd_soc_control_type control_type; - - enum adav80x_clk_src clk_src; - unsigned int sysclk; - enum adav80x_pll_src pll_src; - - unsigned int dai_fmt[2]; - unsigned int rate; - bool deemph; - bool sysclk_pd[3]; -}; - -static const char *adav80x_mux_text[] = { - "ADC", - "Playback", - "Aux Playback", -}; - -static const unsigned int adav80x_mux_values[] = { - 0, 2, 3, -}; - -#define ADAV80X_MUX_ENUM_DECL(name, reg, shift) \ - SOC_VALUE_ENUM_DOUBLE_DECL(name, reg, shift, 7, \ - ARRAY_SIZE(adav80x_mux_text), adav80x_mux_text, \ - adav80x_mux_values) - -static ADAV80X_MUX_ENUM_DECL(adav80x_aux_capture_enum, ADAV80X_DPATH_CTRL1, 0); -static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3); -static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3); - -static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_aux_capture_enum); -static const struct snd_kcontrol_new adav80x_capture_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_capture_enum); -static const struct snd_kcontrol_new adav80x_dac_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_dac_enum); - -#define ADAV80X_MUX(name, ctrl) \ - SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) - -static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = { - SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1), - SND_SOC_DAPM_ADC("ADC", NULL, ADAV80X_ADC_CTRL1, 5, 1), - - SND_SOC_DAPM_PGA("Right PGA", ADAV80X_ADC_CTRL1, 0, 1, NULL, 0), - SND_SOC_DAPM_PGA("Left PGA", ADAV80X_ADC_CTRL1, 1, 1, NULL, 0), - - SND_SOC_DAPM_AIF_OUT("AIFOUT", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("AIFIN", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), - - SND_SOC_DAPM_AIF_OUT("AIFAUXOUT", "Aux Capture", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("AIFAUXIN", "Aux Playback", 0, SND_SOC_NOPM, 0, 0), - - ADAV80X_MUX("Aux Capture Select", &adav80x_aux_capture_mux_ctrl), - ADAV80X_MUX("Capture Select", &adav80x_capture_mux_ctrl), - ADAV80X_MUX("DAC Select", &adav80x_dac_mux_ctrl), - - SND_SOC_DAPM_INPUT("VINR"), - SND_SOC_DAPM_INPUT("VINL"), - SND_SOC_DAPM_OUTPUT("VOUTR"), - SND_SOC_DAPM_OUTPUT("VOUTL"), - - SND_SOC_DAPM_SUPPLY("SYSCLK", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("PLL1", ADAV80X_PLL_CTRL1, 2, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("PLL2", ADAV80X_PLL_CTRL1, 3, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("OSC", ADAV80X_PLL_CTRL1, 1, 1, NULL, 0), -}; - -static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) -{ - struct snd_soc_codec *codec = source->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - const char *clk; - - switch (adav80x->clk_src) { - case ADAV80X_CLK_PLL1: - clk = "PLL1"; - break; - case ADAV80X_CLK_PLL2: - clk = "PLL2"; - break; - case ADAV80X_CLK_XTAL: - clk = "OSC"; - break; - default: - return 0; - } - - return strcmp(source->name, clk) == 0; -} - -static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) -{ - struct snd_soc_codec *codec = source->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL; -} - - -static const struct snd_soc_dapm_route adav80x_dapm_routes[] = { - { "DAC Select", "ADC", "ADC" }, - { "DAC Select", "Playback", "AIFIN" }, - { "DAC Select", "Aux Playback", "AIFAUXIN" }, - { "DAC", NULL, "DAC Select" }, - - { "Capture Select", "ADC", "ADC" }, - { "Capture Select", "Playback", "AIFIN" }, - { "Capture Select", "Aux Playback", "AIFAUXIN" }, - { "AIFOUT", NULL, "Capture Select" }, - - { "Aux Capture Select", "ADC", "ADC" }, - { "Aux Capture Select", "Playback", "AIFIN" }, - { "Aux Capture Select", "Aux Playback", "AIFAUXIN" }, - { "AIFAUXOUT", NULL, "Aux Capture Select" }, - - { "VOUTR", NULL, "DAC" }, - { "VOUTL", NULL, "DAC" }, - - { "Left PGA", NULL, "VINL" }, - { "Right PGA", NULL, "VINR" }, - { "ADC", NULL, "Left PGA" }, - { "ADC", NULL, "Right PGA" }, - - { "SYSCLK", NULL, "PLL1", adav80x_dapm_sysclk_check }, - { "SYSCLK", NULL, "PLL2", adav80x_dapm_sysclk_check }, - { "SYSCLK", NULL, "OSC", adav80x_dapm_sysclk_check }, - { "PLL1", NULL, "OSC", adav80x_dapm_pll_check }, - { "PLL2", NULL, "OSC", adav80x_dapm_pll_check }, - - { "ADC", NULL, "SYSCLK" }, - { "DAC", NULL, "SYSCLK" }, - { "AIFOUT", NULL, "SYSCLK" }, - { "AIFAUXOUT", NULL, "SYSCLK" }, - { "AIFIN", NULL, "SYSCLK" }, - { "AIFAUXIN", NULL, "SYSCLK" }, -}; - -static int adav80x_set_deemph(struct snd_soc_codec *codec) -{ - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - if (adav80x->deemph) { - switch (adav80x->rate) { - case 32000: - val = ADAV80X_DAC_CTRL2_DEEMPH_32; - break; - case 44100: - val = ADAV80X_DAC_CTRL2_DEEMPH_44; - break; - case 48000: - case 64000: - case 88200: - case 96000: - val = ADAV80X_DAC_CTRL2_DEEMPH_48; - break; - default: - val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; - break; - } - } else { - val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; - } - - return snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, - ADAV80X_DAC_CTRL2_DEEMPH_MASK, val); -} - -static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int deemph = ucontrol->value.enumerated.item[0]; - - if (deemph > 1) - return -EINVAL; - - adav80x->deemph = deemph; - - return adav80x_set_deemph(codec); -} - -static int adav80x_get_deemph(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.enumerated.item[0] = adav80x->deemph; - return 0; -}; - -static const DECLARE_TLV_DB_SCALE(adav80x_inpga_tlv, 0, 50, 0); -static const DECLARE_TLV_DB_MINMAX(adav80x_digital_tlv, -9563, 0); - -static const struct snd_kcontrol_new adav80x_controls[] = { - SOC_DOUBLE_R_TLV("Master Playback Volume", ADAV80X_DAC_L_VOL, - ADAV80X_DAC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv), - SOC_DOUBLE_R_TLV("Master Capture Volume", ADAV80X_ADC_L_VOL, - ADAV80X_ADC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv), - - SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAV80X_PGA_L_VOL, - ADAV80X_PGA_R_VOL, 0, 0x30, 0, adav80x_inpga_tlv), - - SOC_DOUBLE("Master Playback Switch", ADAV80X_DAC_CTRL1, 0, 1, 1, 0), - SOC_DOUBLE("Master Capture Switch", ADAV80X_ADC_CTRL1, 2, 3, 1, 1), - - SOC_SINGLE("ADC High Pass Filter Switch", ADAV80X_ADC_CTRL1, 6, 1, 0), - - SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0, - adav80x_get_deemph, adav80x_put_deemph), -}; - -static unsigned int adav80x_port_ctrl_regs[2][2] = { - { ADAV80X_REC_CTRL, ADAV80X_PLAYBACK_CTRL, }, - { ADAV80X_AUX_OUT_CTRL, ADAV80X_AUX_IN_CTRL }, -}; - -static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct snd_soc_codec *codec = dai->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int capture = 0x00; - unsigned int playback = 0x00; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - capture |= ADAV80X_CAPTURE_MODE_MASTER; - playback |= ADAV80X_PLAYBACK_MODE_MASTER; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - capture |= ADAV80X_CAPTURE_MODE_I2S; - playback |= ADAV80X_PLAYBACK_MODE_I2S; - break; - case SND_SOC_DAIFMT_LEFT_J: - capture |= ADAV80X_CAPTURE_MODE_LEFT_J; - playback |= ADAV80X_PLAYBACK_MODE_LEFT_J; - break; - case SND_SOC_DAIFMT_RIGHT_J: - capture |= ADAV80X_CAPTURE_MODE_RIGHT_J; - playback |= ADAV80X_PLAYBACK_MODE_RIGHT_J_24; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], - ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER, - capture); - snd_soc_write(codec, adav80x_port_ctrl_regs[dai->id][1], playback); - - adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK; - - return 0; -} - -static int adav80x_set_adc_clock(struct snd_soc_codec *codec, - unsigned int sample_rate) -{ - unsigned int val; - - if (sample_rate <= 48000) - val = ADAV80X_ADC_CTRL1_MODULATOR_128FS; - else - val = ADAV80X_ADC_CTRL1_MODULATOR_64FS; - - snd_soc_update_bits(codec, ADAV80X_ADC_CTRL1, - ADAV80X_ADC_CTRL1_MODULATOR_MASK, val); - - return 0; -} - -static int adav80x_set_dac_clock(struct snd_soc_codec *codec, - unsigned int sample_rate) -{ - unsigned int val; - - if (sample_rate <= 48000) - val = ADAV80X_DAC_CTRL2_DIV1 | ADAV80X_DAC_CTRL2_INTERPOL_256FS; - else - val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS; - - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, - ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK, - val); - - return 0; -} - -static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec, - struct snd_soc_dai *dai, snd_pcm_format_t format) -{ - unsigned int val; - - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: - val = ADAV80X_CAPTURE_WORD_LEN16; - break; - case SNDRV_PCM_FORMAT_S18_3LE: - val = ADAV80X_CAPTRUE_WORD_LEN18; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - val = ADAV80X_CAPTURE_WORD_LEN20; - break; - case SNDRV_PCM_FORMAT_S24_LE: - val = ADAV80X_CAPTURE_WORD_LEN24; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], - ADAV80X_CAPTURE_WORD_LEN_MASK, val); - - return 0; -} - -static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec, - struct snd_soc_dai *dai, snd_pcm_format_t format) -{ - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J) - return 0; - - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: - val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16; - break; - case SNDRV_PCM_FORMAT_S18_3LE: - val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20; - break; - case SNDRV_PCM_FORMAT_S24_LE: - val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][1], - ADAV80X_PLAYBACK_MODE_MASK, val); - - return 0; -} - -static int adav80x_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 adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int rate = params_rate(params); - - if (rate * 256 != adav80x->sysclk) - return -EINVAL; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - adav80x_set_playback_pcm_format(codec, dai, - params_format(params)); - adav80x_set_dac_clock(codec, rate); - } else { - adav80x_set_capture_pcm_format(codec, dai, - params_format(params)); - adav80x_set_adc_clock(codec, rate); - } - adav80x->rate = rate; - adav80x_set_deemph(codec); - - return 0; -} - -static int adav80x_set_sysclk(struct snd_soc_codec *codec, - int clk_id, unsigned int freq, int dir) -{ - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - if (dir == SND_SOC_CLOCK_IN) { - switch (clk_id) { - case ADAV80X_CLK_XIN: - case ADAV80X_CLK_XTAL: - case ADAV80X_CLK_MCLKI: - case ADAV80X_CLK_PLL1: - case ADAV80X_CLK_PLL2: - break; - default: - return -EINVAL; - } - - adav80x->sysclk = freq; - - if (adav80x->clk_src != clk_id) { - unsigned int iclk_ctrl1, iclk_ctrl2; - - adav80x->clk_src = clk_id; - if (clk_id == ADAV80X_CLK_XTAL) - clk_id = ADAV80X_CLK_XIN; - - iclk_ctrl1 = ADAV80X_ICLK_CTRL1_DAC_SRC(clk_id) | - ADAV80X_ICLK_CTRL1_ADC_SRC(clk_id) | - ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id); - iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id); - - snd_soc_write(codec, ADAV80X_ICLK_CTRL1, iclk_ctrl1); - snd_soc_write(codec, ADAV80X_ICLK_CTRL2, iclk_ctrl2); - - snd_soc_dapm_sync(&codec->dapm); - } - } else { - unsigned int mask; - - switch (clk_id) { - case ADAV80X_CLK_SYSCLK1: - case ADAV80X_CLK_SYSCLK2: - case ADAV80X_CLK_SYSCLK3: - break; - default: - return -EINVAL; - } - - clk_id -= ADAV80X_CLK_SYSCLK1; - mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id); - - if (freq == 0) { - snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, mask); - adav80x->sysclk_pd[clk_id] = true; - } else { - snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, 0); - adav80x->sysclk_pd[clk_id] = false; - } - - if (adav80x->sysclk_pd[0]) - snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); - else - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); - - if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) - snd_soc_dapm_disable_pin(&codec->dapm, "PLL2"); - else - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); - - snd_soc_dapm_sync(&codec->dapm); - } - - return 0; -} - -static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, - int source, unsigned int freq_in, unsigned int freq_out) -{ - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int pll_ctrl1 = 0; - unsigned int pll_ctrl2 = 0; - unsigned int pll_src; - - switch (source) { - case ADAV80X_PLL_SRC_XTAL: - case ADAV80X_PLL_SRC_XIN: - case ADAV80X_PLL_SRC_MCLKI: - break; - default: - return -EINVAL; - } - - if (!freq_out) - return 0; - - switch (freq_in) { - case 27000000: - break; - case 54000000: - if (source == ADAV80X_PLL_SRC_XIN) { - pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV; - break; - } - default: - return -EINVAL; - } - - if (freq_out > 12288000) { - pll_ctrl2 |= ADAV80X_PLL_CTRL2_DOUB(pll_id); - freq_out /= 2; - } - - /* freq_out = sample_rate * 256 */ - switch (freq_out) { - case 8192000: - pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_32(pll_id); - break; - case 11289600: - pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_44(pll_id); - break; - case 12288000: - pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_48(pll_id); - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ADAV80X_PLL_CTRL1, ADAV80X_PLL_CTRL1_PLLDIV, - pll_ctrl1); - snd_soc_update_bits(codec, ADAV80X_PLL_CTRL2, - ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2); - - if (source != adav80x->pll_src) { - if (source == ADAV80X_PLL_SRC_MCLKI) - pll_src = ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll_id); - else - pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id); - - snd_soc_update_bits(codec, ADAV80X_PLL_CLK_SRC, - ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src); - - adav80x->pll_src = source; - - snd_soc_dapm_sync(&codec->dapm); - } - - return 0; -} - -static int adav80x_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - unsigned int mask = ADAV80X_DAC_CTRL1_PD; - - switch (level) { - case SND_SOC_BIAS_ON: - break; - case SND_SOC_BIAS_PREPARE: - break; - case SND_SOC_BIAS_STANDBY: - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, 0x00); - break; - case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, mask); - break; - } - - codec->dapm.bias_level = level; - return 0; -} - -/* Enforce the same sample rate on all audio interfaces */ -static int adav80x_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - if (!codec->active || !adav80x->rate) - return 0; - - return snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, adav80x->rate, adav80x->rate); -} - -static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - if (!codec->active) - adav80x->rate = 0; -} - -static const struct snd_soc_dai_ops adav80x_dai_ops = { - .set_fmt = adav80x_set_dai_fmt, - .hw_params = adav80x_hw_params, - .startup = adav80x_dai_startup, - .shutdown = adav80x_dai_shutdown, -}; - -#define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | \ - SNDRV_PCM_RATE_96000) - -#define ADAV80X_CAPTURE_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) - -#define ADAV80X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) - -static struct snd_soc_dai_driver adav80x_dais[] = { - { - .name = "adav80x-hifi", - .id = 0, - .playback = { - .stream_name = "HiFi Playback", - .channels_min = 2, - .channels_max = 2, - .rates = ADAV80X_PLAYBACK_RATES, - .formats = ADAV80X_FORMATS, - }, - .capture = { - .stream_name = "HiFi Capture", - .channels_min = 2, - .channels_max = 2, - .rates = ADAV80X_CAPTURE_RATES, - .formats = ADAV80X_FORMATS, - }, - .ops = &adav80x_dai_ops, - }, - { - .name = "adav80x-aux", - .id = 1, - .playback = { - .stream_name = "Aux Playback", - .channels_min = 2, - .channels_max = 2, - .rates = ADAV80X_PLAYBACK_RATES, - .formats = ADAV80X_FORMATS, - }, - .capture = { - .stream_name = "Aux Capture", - .channels_min = 2, - .channels_max = 2, - .rates = ADAV80X_CAPTURE_RATES, - .formats = ADAV80X_FORMATS, - }, - .ops = &adav80x_dai_ops, - }, -}; - -static int adav80x_probe(struct snd_soc_codec *codec) -{ - int ret; - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - - ret = snd_soc_codec_set_cache_io(codec, 7, 9, adav80x->control_type); - if (ret) { - dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); - return ret; - } - - /* Force PLLs on for SYSCLK output */ - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); - - /* Power down S/PDIF receiver, since it is currently not supported */ - snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x20); - /* Disable DAC zero flag */ - snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6); - - return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -} - -static int adav80x_suspend(struct snd_soc_codec *codec, pm_message_t state) -{ - return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - -static int adav80x_resume(struct snd_soc_codec *codec) -{ - adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - codec->cache_sync = 1; - snd_soc_cache_sync(codec); - - return 0; -} - -static int adav80x_remove(struct snd_soc_codec *codec) -{ - return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - -static struct snd_soc_codec_driver adav80x_codec_driver = { - .probe = adav80x_probe, - .remove = adav80x_remove, - .suspend = adav80x_suspend, - .resume = adav80x_resume, - .set_bias_level = adav80x_set_bias_level, - - .set_pll = adav80x_set_pll, - .set_sysclk = adav80x_set_sysclk, - - .reg_word_size = sizeof(u8), - .reg_cache_size = ARRAY_SIZE(adav80x_default_regs), - .reg_cache_default = adav80x_default_regs, - - .controls = adav80x_controls, - .num_controls = ARRAY_SIZE(adav80x_controls), - .dapm_widgets = adav80x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets), - .dapm_routes = adav80x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), -}; - -static int __devinit adav80x_bus_probe(struct device *dev, - enum snd_soc_control_type control_type) -{ - struct adav80x *adav80x; - int ret; - - adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); - if (!adav80x) - return -ENOMEM; - - dev_set_drvdata(dev, adav80x); - adav80x->control_type = control_type; - - ret = snd_soc_register_codec(dev, &adav80x_codec_driver, - adav80x_dais, ARRAY_SIZE(adav80x_dais)); - if (ret) - kfree(adav80x); - - return ret; -} - -static int __devexit adav80x_bus_remove(struct device *dev) -{ - snd_soc_unregister_codec(dev); - kfree(dev_get_drvdata(dev)); - return 0; -} - -#if defined(CONFIG_SPI_MASTER) -static int __devinit adav80x_spi_probe(struct spi_device *spi) -{ - return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); -} - -static int __devexit adav80x_spi_remove(struct spi_device *spi) -{ - return adav80x_bus_remove(&spi->dev); -} - -static struct spi_driver adav80x_spi_driver = { - .driver = { - .name = "adav801", - .owner = THIS_MODULE, - }, - .probe = adav80x_spi_probe, - .remove = __devexit_p(adav80x_spi_remove), -}; -#endif - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static const struct i2c_device_id adav80x_id[] = { - { "adav803", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adav80x_id); - -static int __devinit adav80x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return adav80x_bus_probe(&client->dev, SND_SOC_I2C); -} - -static int __devexit adav80x_i2c_remove(struct i2c_client *client) -{ - return adav80x_bus_remove(&client->dev); -} - -static struct i2c_driver adav80x_i2c_driver = { - .driver = { - .name = "adav803", - .owner = THIS_MODULE, - }, - .probe = adav80x_i2c_probe, - .remove = __devexit_p(adav80x_i2c_remove), - .id_table = adav80x_id, -}; -#endif - -static int __init adav80x_init(void) -{ - int ret = 0; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&adav80x_i2c_driver); - if (ret) - return ret; -#endif - -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&adav80x_spi_driver); -#endif - - return ret; -} -module_init(adav80x_init); - -static void __exit adav80x_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&adav80x_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&adav80x_spi_driver); -#endif -} -module_exit(adav80x_exit); - -MODULE_DESCRIPTION("ASoC ADAV80x driver"); -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_AUTHOR("Yi Li >"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/adav80x.h b/trunk/sound/soc/codecs/adav80x.h deleted file mode 100644 index adb0fc76d4e3..000000000000 --- a/trunk/sound/soc/codecs/adav80x.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * header file for ADAV80X parts - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _ADAV80X_H -#define _ADAV80X_H - -enum adav80x_pll_src { - ADAV80X_PLL_SRC_XIN, - ADAV80X_PLL_SRC_XTAL, - ADAV80X_PLL_SRC_MCLKI, -}; - -enum adav80x_pll { - ADAV80X_PLL1 = 0, - ADAV80X_PLL2 = 1, -}; - -enum adav80x_clk_src { - ADAV80X_CLK_XIN = 0, - ADAV80X_CLK_MCLKI = 1, - ADAV80X_CLK_PLL1 = 2, - ADAV80X_CLK_PLL2 = 3, - ADAV80X_CLK_XTAL = 6, - - ADAV80X_CLK_SYSCLK1 = 6, - ADAV80X_CLK_SYSCLK2 = 7, - ADAV80X_CLK_SYSCLK3 = 8, -}; - -#endif diff --git a/trunk/sound/soc/codecs/ak4641.c b/trunk/sound/soc/codecs/ak4641.c index 7a64e58cddc4..ed96f247c2da 100644 --- a/trunk/sound/soc/codecs/ak4641.c +++ b/trunk/sound/soc/codecs/ak4641.c @@ -457,7 +457,7 @@ static struct snd_soc_dai_ops ak4641_pcm_dai_ops = { .set_sysclk = ak4641_set_dai_sysclk, }; -static struct snd_soc_dai_driver ak4641_dai[] = { +struct snd_soc_dai_driver ak4641_dai[] = { { .name = "ak4641-hifi", .id = 1, diff --git a/trunk/sound/soc/codecs/cs4270.c b/trunk/sound/soc/codecs/cs4270.c index 6cc8678f49f3..0206a17d7283 100644 --- a/trunk/sound/soc/codecs/cs4270.c +++ b/trunk/sound/soc/codecs/cs4270.c @@ -636,7 +636,10 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec) #endif /* CONFIG_PM */ /* - * ASoC codec driver structure + * ASoC codec device structure + * + * Assign this variable to the codec_dev field of the machine driver's + * snd_soc_device structure. */ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { .probe = cs4270_probe, diff --git a/trunk/sound/soc/codecs/max98088.c b/trunk/sound/soc/codecs/max98088.c index ac65a2d36408..4173b67c94d1 100644 --- a/trunk/sound/soc/codecs/max98088.c +++ b/trunk/sound/soc/codecs/max98088.c @@ -1397,6 +1397,8 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai, if (freq == max98088->sysclk) return 0; + max98088->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 30MHz).. diff --git a/trunk/sound/soc/codecs/max98095.c b/trunk/sound/soc/codecs/max98095.c index 668434d44303..e1d282d477da 100644 --- a/trunk/sound/soc/codecs/max98095.c +++ b/trunk/sound/soc/codecs/max98095.c @@ -1517,6 +1517,8 @@ static int max98095_dai_set_sysclk(struct snd_soc_dai *dai, 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).. @@ -2259,11 +2261,11 @@ static int max98095_probe(struct snd_soc_codec *codec) ret = snd_soc_read(codec, M98095_0FF_REV_ID); if (ret < 0) { - dev_err(codec->dev, "Failure reading hardware revision: %d\n", + dev_err(codec->dev, "Failed to read device revision: %d\n", ret); goto err_access; } - dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A'); + dev_info(codec->dev, "revision %c\n", ret + 'A'); snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); @@ -2340,8 +2342,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c, max98095->control_data = i2c; max98095->pdata = i2c->dev.platform_data; - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98095, - max98095_dai, ARRAY_SIZE(max98095_dai)); + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_max98095, &max98095_dai[0], 3); if (ret < 0) kfree(max98095); return ret; diff --git a/trunk/sound/soc/codecs/sta32x.c b/trunk/sound/soc/codecs/sta32x.c deleted file mode 100644 index 409d89d1f34c..000000000000 --- a/trunk/sound/soc/codecs/sta32x.c +++ /dev/null @@ -1,917 +0,0 @@ -/* - * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system - * - * Copyright: 2011 Raumfeld GmbH - * Author: Johannes Stezenbach - * - * based on code from: - * Wolfson Microelectronics PLC. - * Mark Brown - * Freescale Semiconductor, Inc. - * Timur Tabi - * - * This program is free software; 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sta32x.h" - -#define STA32X_RATES (SNDRV_PCM_RATE_32000 | \ - SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | \ - SNDRV_PCM_RATE_88200 | \ - SNDRV_PCM_RATE_96000 | \ - SNDRV_PCM_RATE_176400 | \ - SNDRV_PCM_RATE_192000) - -#define STA32X_FORMATS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) - -/* Power-up register defaults */ -static const u8 sta32x_regs[STA32X_REGISTER_COUNT] = { - 0x63, 0x80, 0xc2, 0x40, 0xc2, 0x5c, 0x10, 0xff, 0x60, 0x60, - 0x60, 0x80, 0x00, 0x00, 0x00, 0x40, 0x80, 0x77, 0x6a, 0x69, - 0x6a, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, - 0xc0, 0xf3, 0x33, 0x00, 0x0c, -}; - -/* regulator power supply names */ -static const char *sta32x_supply_names[] = { - "Vdda", /* analog supply, 3.3VV */ - "Vdd3", /* digital supply, 3.3V */ - "Vcc" /* power amp spply, 10V - 36V */ -}; - -/* codec private data */ -struct sta32x_priv { - struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)]; - struct snd_soc_codec *codec; - - unsigned int mclk; - unsigned int format; -}; - -static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1); -static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1); -static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0); - -static const char *sta32x_drc_ac[] = { - "Anti-Clipping", "Dynamic Range Compression" }; -static const char *sta32x_auto_eq_mode[] = { - "User", "Preset", "Loudness" }; -static const char *sta32x_auto_gc_mode[] = { - "User", "AC no clipping", "AC limited clipping (10%)", - "DRC nighttime listening mode" }; -static const char *sta32x_auto_xo_mode[] = { - "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz", - "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" }; -static const char *sta32x_preset_eq_mode[] = { - "Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft", - "Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1", - "Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2", - "Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7", - "Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12", - "Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" }; -static const char *sta32x_limiter_select[] = { - "Limiter Disabled", "Limiter #1", "Limiter #2" }; -static const char *sta32x_limiter_attack_rate[] = { - "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024", - "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752", - "0.0645", "0.0564", "0.0501", "0.0451" }; -static const char *sta32x_limiter_release_rate[] = { - "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299", - "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137", - "0.0134", "0.0117", "0.0110", "0.0104" }; - -static const unsigned int sta32x_limiter_ac_attack_tlv[] = { - TLV_DB_RANGE_HEAD(2), - 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), - 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), -}; - -static const unsigned int sta32x_limiter_ac_release_tlv[] = { - TLV_DB_RANGE_HEAD(5), - 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), - 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), - 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), - 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), - 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), -}; - -static const unsigned int sta32x_limiter_drc_attack_tlv[] = { - TLV_DB_RANGE_HEAD(3), - 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), - 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), - 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), -}; - -static const unsigned int sta32x_limiter_drc_release_tlv[] = { - TLV_DB_RANGE_HEAD(5), - 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), - 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), - 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), - 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), - 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), -}; - -static const struct soc_enum sta32x_drc_ac_enum = - SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, - 2, sta32x_drc_ac); -static const struct soc_enum sta32x_auto_eq_enum = - SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, - 3, sta32x_auto_eq_mode); -static const struct soc_enum sta32x_auto_gc_enum = - SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, - 4, sta32x_auto_gc_mode); -static const struct soc_enum sta32x_auto_xo_enum = - SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, - 16, sta32x_auto_xo_mode); -static const struct soc_enum sta32x_preset_eq_enum = - SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, - 32, sta32x_preset_eq_mode); -static const struct soc_enum sta32x_limiter_ch1_enum = - SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch2_enum = - SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch3_enum = - SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter1_attack_rate_enum = - SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT, - 16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter2_attack_rate_enum = - SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT, - 16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter1_release_rate_enum = - SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT, - 16, sta32x_limiter_release_rate); -static const struct soc_enum sta32x_limiter2_release_rate_enum = - SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, - 16, sta32x_limiter_release_rate); - -/* byte array controls for setting biquad, mixer, scaling coefficients; - * for biquads all five coefficients need to be set in one go, - * mixer and pre/postscale coefs can be set individually; - * each coef is 24bit, the bytes are ordered in the same way - * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0) - */ - -static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - int numcoef = kcontrol->private_value >> 16; - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = 3 * numcoef; - return 0; -} - -static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int numcoef = kcontrol->private_value >> 16; - int index = kcontrol->private_value & 0xffff; - unsigned int cfud; - int i; - - /* preserve reserved bits in STA32X_CFUD */ - cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; - /* chip documentation does not say if the bits are self clearing, - * so do it explicitly */ - snd_soc_write(codec, STA32X_CFUD, cfud); - - snd_soc_write(codec, STA32X_CFADDR2, index); - if (numcoef == 1) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x04); - else if (numcoef == 5) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x08); - else - return -EINVAL; - for (i = 0; i < 3 * numcoef; i++) - ucontrol->value.bytes.data[i] = - snd_soc_read(codec, STA32X_B1CF1 + i); - - return 0; -} - -static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int numcoef = kcontrol->private_value >> 16; - int index = kcontrol->private_value & 0xffff; - unsigned int cfud; - int i; - - /* preserve reserved bits in STA32X_CFUD */ - cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; - /* chip documentation does not say if the bits are self clearing, - * so do it explicitly */ - snd_soc_write(codec, STA32X_CFUD, cfud); - - snd_soc_write(codec, STA32X_CFADDR2, index); - for (i = 0; i < 3 * numcoef; i++) - snd_soc_write(codec, STA32X_B1CF1 + i, - ucontrol->value.bytes.data[i]); - if (numcoef == 1) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); - else if (numcoef == 5) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x02); - else - return -EINVAL; - - return 0; -} - -#define SINGLE_COEF(xname, index) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = sta32x_coefficient_info, \ - .get = sta32x_coefficient_get,\ - .put = sta32x_coefficient_put, \ - .private_value = index | (1 << 16) } - -#define BIQUAD_COEFS(xname, index) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = sta32x_coefficient_info, \ - .get = sta32x_coefficient_get,\ - .put = sta32x_coefficient_put, \ - .private_value = index | (5 << 16) } - -static const struct snd_kcontrol_new sta32x_snd_controls[] = { -SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv), -SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1), -SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1), -SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1), -SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1), -SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv), -SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv), -SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv), -SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0), -SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum), -SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0), -SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0), -SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0), -SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0), -SOC_ENUM("Automode EQ", sta32x_auto_eq_enum), -SOC_ENUM("Automode GC", sta32x_auto_gc_enum), -SOC_ENUM("Automode XO", sta32x_auto_xo_enum), -SOC_ENUM("Preset EQ", sta32x_preset_eq_enum), -SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0), -SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0), -SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0), -SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0), -SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), -SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), -SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), -SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum), -SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum), -SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum), -SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv), -SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv), -SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum), -SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum), -SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), -SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), - -/* depending on mode, the attack/release thresholds have - * two different enum definitions; provide both - */ -SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT, - 16, 0, sta32x_limiter_ac_attack_tlv), -SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT, - 16, 0, sta32x_limiter_ac_attack_tlv), -SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT, - 16, 0, sta32x_limiter_ac_release_tlv), -SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, - 16, 0, sta32x_limiter_ac_release_tlv), -SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT, - 16, 0, sta32x_limiter_drc_attack_tlv), -SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT, - 16, 0, sta32x_limiter_drc_attack_tlv), -SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT, - 16, 0, sta32x_limiter_drc_release_tlv), -SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, - 16, 0, sta32x_limiter_drc_release_tlv), - -BIQUAD_COEFS("Ch1 - Biquad 1", 0), -BIQUAD_COEFS("Ch1 - Biquad 2", 5), -BIQUAD_COEFS("Ch1 - Biquad 3", 10), -BIQUAD_COEFS("Ch1 - Biquad 4", 15), -BIQUAD_COEFS("Ch2 - Biquad 1", 20), -BIQUAD_COEFS("Ch2 - Biquad 2", 25), -BIQUAD_COEFS("Ch2 - Biquad 3", 30), -BIQUAD_COEFS("Ch2 - Biquad 4", 35), -BIQUAD_COEFS("High-pass", 40), -BIQUAD_COEFS("Low-pass", 45), -SINGLE_COEF("Ch1 - Prescale", 50), -SINGLE_COEF("Ch2 - Prescale", 51), -SINGLE_COEF("Ch1 - Postscale", 52), -SINGLE_COEF("Ch2 - Postscale", 53), -SINGLE_COEF("Ch3 - Postscale", 54), -SINGLE_COEF("Thermal warning - Postscale", 55), -SINGLE_COEF("Ch1 - Mix 1", 56), -SINGLE_COEF("Ch1 - Mix 2", 57), -SINGLE_COEF("Ch2 - Mix 1", 58), -SINGLE_COEF("Ch2 - Mix 2", 59), -SINGLE_COEF("Ch3 - Mix 1", 60), -SINGLE_COEF("Ch3 - Mix 2", 61), -}; - -static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = { -SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_OUTPUT("LEFT"), -SND_SOC_DAPM_OUTPUT("RIGHT"), -SND_SOC_DAPM_OUTPUT("SUB"), -}; - -static const struct snd_soc_dapm_route sta32x_dapm_routes[] = { - { "LEFT", NULL, "DAC" }, - { "RIGHT", NULL, "DAC" }, - { "SUB", NULL, "DAC" }, -}; - -/* MCLK interpolation ratio per fs */ -static struct { - int fs; - int ir; -} interpolation_ratios[] = { - { 32000, 0 }, - { 44100, 0 }, - { 48000, 0 }, - { 88200, 1 }, - { 96000, 1 }, - { 176400, 2 }, - { 192000, 2 }, -}; - -/* MCLK to fs clock ratios */ -static struct { - int ratio; - int mcs; -} mclk_ratios[3][7] = { - { { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 }, - { 128, 4 }, { 576, 5 }, { 0, 0 } }, - { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, - { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, -}; - - -/** - * sta32x_set_dai_sysclk - configure MCLK - * @codec_dai: the codec DAI - * @clk_id: the clock ID (ignored) - * @freq: the MCLK input frequency - * @dir: the clock direction (ignored) - * - * The value of MCLK is used to determine which sample rates are supported - * by the STA32X, based on the mclk_ratios table. - * - * This function must be called by the machine driver's 'startup' function, - * otherwise the list of supported sample rates will not be available in - * time for ALSA. - * - * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause - * theoretically possible sample rates to be enabled. Call it again with a - * proper value set one the external clock is set (most probably you would do - * that from a machine's driver 'hw_param' hook. - */ -static int sta32x_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 sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - int i, j, ir, fs; - unsigned int rates = 0; - unsigned int rate_min = -1; - unsigned int rate_max = 0; - - pr_debug("mclk=%u\n", freq); - sta32x->mclk = freq; - - if (sta32x->mclk) { - for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { - ir = interpolation_ratios[i].ir; - fs = interpolation_ratios[i].fs; - for (j = 0; mclk_ratios[ir][j].ratio; j++) { - if (mclk_ratios[ir][j].ratio * fs == freq) { - rates |= snd_pcm_rate_to_rate_bit(fs); - if (fs < rate_min) - rate_min = fs; - if (fs > rate_max) - rate_max = fs; - } - } - } - /* FIXME: soc should support a rate list */ - rates &= ~SNDRV_PCM_RATE_KNOT; - - if (!rates) { - dev_err(codec->dev, "could not find a valid sample rate\n"); - return -EINVAL; - } - } else { - /* enable all possible rates */ - rates = STA32X_RATES; - rate_min = 32000; - rate_max = 192000; - } - - codec_dai->driver->playback.rates = rates; - codec_dai->driver->playback.rate_min = rate_min; - codec_dai->driver->playback.rate_max = rate_max; - return 0; -} - -/** - * sta32x_set_dai_fmt - configure the codec for the selected audio format - * @codec_dai: the codec DAI - * @fmt: a SND_SOC_DAIFMT_x value indicating the data format - * - * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the - * codec accordingly. - */ -static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - u8 confb = snd_soc_read(codec, STA32X_CONFB); - - pr_debug("\n"); - confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM); - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_RIGHT_J: - case SND_SOC_DAIFMT_LEFT_J: - sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - confb |= STA32X_CONFB_C2IM; - break; - case SND_SOC_DAIFMT_NB_IF: - confb |= STA32X_CONFB_C1IM; - break; - default: - return -EINVAL; - } - - snd_soc_write(codec, STA32X_CONFB, confb); - return 0; -} - -/** - * sta32x_hw_params - program the STA32X with the given hardware parameters. - * @substream: the audio stream - * @params: the hardware parameters to set - * @dai: the SOC DAI (ignored) - * - * This function programs the hardware with the values provided. - * Specifically, the sample rate and the data format. - */ -static int sta32x_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 sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - unsigned int rate; - int i, mcs = -1, ir = -1; - u8 confa, confb; - - rate = params_rate(params); - pr_debug("rate: %u\n", rate); - for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) - if (interpolation_ratios[i].fs == rate) - ir = interpolation_ratios[i].ir; - if (ir < 0) - return -EINVAL; - for (i = 0; mclk_ratios[ir][i].ratio; i++) - if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) - mcs = mclk_ratios[ir][i].mcs; - if (mcs < 0) - return -EINVAL; - - confa = snd_soc_read(codec, STA32X_CONFA); - confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK); - confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT); - - confb = snd_soc_read(codec, STA32X_CONFB); - confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_S24_BE: - case SNDRV_PCM_FORMAT_S24_3LE: - case SNDRV_PCM_FORMAT_S24_3BE: - pr_debug("24bit\n"); - /* fall through */ - case SNDRV_PCM_FORMAT_S32_LE: - case SNDRV_PCM_FORMAT_S32_BE: - pr_debug("24bit or 32bit\n"); - switch (sta32x->format) { - case SND_SOC_DAIFMT_I2S: - confb |= 0x0; - break; - case SND_SOC_DAIFMT_LEFT_J: - confb |= 0x1; - break; - case SND_SOC_DAIFMT_RIGHT_J: - confb |= 0x2; - break; - } - - break; - case SNDRV_PCM_FORMAT_S20_3LE: - case SNDRV_PCM_FORMAT_S20_3BE: - pr_debug("20bit\n"); - switch (sta32x->format) { - case SND_SOC_DAIFMT_I2S: - confb |= 0x4; - break; - case SND_SOC_DAIFMT_LEFT_J: - confb |= 0x5; - break; - case SND_SOC_DAIFMT_RIGHT_J: - confb |= 0x6; - break; - } - - break; - case SNDRV_PCM_FORMAT_S18_3LE: - case SNDRV_PCM_FORMAT_S18_3BE: - pr_debug("18bit\n"); - switch (sta32x->format) { - case SND_SOC_DAIFMT_I2S: - confb |= 0x8; - break; - case SND_SOC_DAIFMT_LEFT_J: - confb |= 0x9; - break; - case SND_SOC_DAIFMT_RIGHT_J: - confb |= 0xa; - break; - } - - break; - case SNDRV_PCM_FORMAT_S16_LE: - case SNDRV_PCM_FORMAT_S16_BE: - pr_debug("16bit\n"); - switch (sta32x->format) { - case SND_SOC_DAIFMT_I2S: - confb |= 0x0; - break; - case SND_SOC_DAIFMT_LEFT_J: - confb |= 0xd; - break; - case SND_SOC_DAIFMT_RIGHT_J: - confb |= 0xe; - break; - } - - break; - default: - return -EINVAL; - } - - snd_soc_write(codec, STA32X_CONFA, confa); - snd_soc_write(codec, STA32X_CONFB, confb); - return 0; -} - -/** - * sta32x_set_bias_level - DAPM callback - * @codec: the codec device - * @level: DAPM power level - * - * This is called by ALSA to put the codec into low power mode - * or to wake it up. If the codec is powered off completely - * all registers must be restored after power on. - */ -static int sta32x_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - int ret; - struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - - pr_debug("level = %d\n", level); - switch (level) { - case SND_SOC_BIAS_ON: - break; - - case SND_SOC_BIAS_PREPARE: - /* Full power on */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); - break; - - case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), - sta32x->supplies); - if (ret != 0) { - dev_err(codec->dev, - "Failed to enable supplies: %d\n", ret); - return ret; - } - - snd_soc_cache_sync(codec); - } - - /* Power up to mute */ - /* FIXME */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); - - break; - - case SND_SOC_BIAS_OFF: - /* The chip runs through the power down sequence for us. */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, - STA32X_CONFF_PWDN); - msleep(300); - - regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), - sta32x->supplies); - break; - } - codec->dapm.bias_level = level; - return 0; -} - -static struct snd_soc_dai_ops sta32x_dai_ops = { - .hw_params = sta32x_hw_params, - .set_sysclk = sta32x_set_dai_sysclk, - .set_fmt = sta32x_set_dai_fmt, -}; - -static struct snd_soc_dai_driver sta32x_dai = { - .name = "STA32X", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = STA32X_RATES, - .formats = STA32X_FORMATS, - }, - .ops = &sta32x_dai_ops, -}; - -#ifdef CONFIG_PM -static int sta32x_suspend(struct snd_soc_codec *codec, pm_message_t state) -{ - sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int sta32x_resume(struct snd_soc_codec *codec) -{ - sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define sta32x_suspend NULL -#define sta32x_resume NULL -#endif - -static int sta32x_probe(struct snd_soc_codec *codec) -{ - struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - int i, ret = 0; - - sta32x->codec = codec; - - /* regulators */ - for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) - sta32x->supplies[i].supply = sta32x_supply_names[i]; - - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sta32x->supplies), - sta32x->supplies); - if (ret != 0) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); - goto err; - } - - ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), - sta32x->supplies); - if (ret != 0) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_get; - } - - /* Tell ASoC what kind of I/O to use to read the registers. ASoC will - * then do the I2C transactions itself. - */ - 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 (ret=%i)\n", ret); - return ret; - } - - /* read reg reset values into cache */ - for (i = 0; i < STA32X_REGISTER_COUNT; i++) - snd_soc_cache_write(codec, i, sta32x_regs[i]); - - /* preserve reset values of reserved register bits */ - snd_soc_cache_write(codec, STA32X_CONFC, - codec->hw_read(codec, STA32X_CONFC)); - snd_soc_cache_write(codec, STA32X_CONFE, - codec->hw_read(codec, STA32X_CONFE)); - snd_soc_cache_write(codec, STA32X_CONFF, - codec->hw_read(codec, STA32X_CONFF)); - snd_soc_cache_write(codec, STA32X_MMUTE, - codec->hw_read(codec, STA32X_MMUTE)); - snd_soc_cache_write(codec, STA32X_AUTO1, - codec->hw_read(codec, STA32X_AUTO1)); - snd_soc_cache_write(codec, STA32X_AUTO3, - codec->hw_read(codec, STA32X_AUTO3)); - snd_soc_cache_write(codec, STA32X_C3CFG, - codec->hw_read(codec, STA32X_C3CFG)); - - /* FIXME enable thermal warning adjustment and recovery */ - snd_soc_update_bits(codec, STA32X_CONFA, - STA32X_CONFA_TWAB | STA32X_CONFA_TWRB, 0); - - /* FIXME select 2.1 mode */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_OCFG_MASK, - 1 << STA32X_CONFF_OCFG_SHIFT); - - /* FIXME channel to output mapping */ - snd_soc_update_bits(codec, STA32X_C1CFG, - STA32X_CxCFG_OM_MASK, - 0 << STA32X_CxCFG_OM_SHIFT); - snd_soc_update_bits(codec, STA32X_C2CFG, - STA32X_CxCFG_OM_MASK, - 1 << STA32X_CxCFG_OM_SHIFT); - snd_soc_update_bits(codec, STA32X_C3CFG, - STA32X_CxCFG_OM_MASK, - 2 << STA32X_CxCFG_OM_SHIFT); - - sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* Bias level configuration will have done an extra enable */ - regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); - - return 0; - -err_get: - regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); -err: - return ret; -} - -static int sta32x_remove(struct snd_soc_codec *codec) -{ - struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - - regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); - regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); - - return 0; -} - -static int sta32x_reg_is_volatile(struct snd_soc_codec *codec, - unsigned int reg) -{ - switch (reg) { - case STA32X_CONFA ... STA32X_L2ATRT: - case STA32X_MPCC1 ... STA32X_FDRC2: - return 0; - } - return 1; -} - -static const struct snd_soc_codec_driver sta32x_codec = { - .probe = sta32x_probe, - .remove = sta32x_remove, - .suspend = sta32x_suspend, - .resume = sta32x_resume, - .reg_cache_size = STA32X_REGISTER_COUNT, - .reg_word_size = sizeof(u8), - .volatile_register = sta32x_reg_is_volatile, - .set_bias_level = sta32x_set_bias_level, - .controls = sta32x_snd_controls, - .num_controls = ARRAY_SIZE(sta32x_snd_controls), - .dapm_widgets = sta32x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sta32x_dapm_widgets), - .dapm_routes = sta32x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(sta32x_dapm_routes), -}; - -static __devinit int sta32x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct sta32x_priv *sta32x; - int ret; - - sta32x = kzalloc(sizeof(struct sta32x_priv), GFP_KERNEL); - if (!sta32x) - return -ENOMEM; - - i2c_set_clientdata(i2c, sta32x); - - ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret); - return ret; - } - - return 0; -} - -static __devexit int sta32x_i2c_remove(struct i2c_client *client) -{ - struct sta32x_priv *sta32x = i2c_get_clientdata(client); - struct snd_soc_codec *codec = sta32x->codec; - - if (codec) - sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); - - regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); - - if (codec) { - snd_soc_unregister_codec(&client->dev); - snd_soc_codec_set_drvdata(codec, NULL); - } - - kfree(sta32x); - return 0; -} - -static const struct i2c_device_id sta32x_i2c_id[] = { - { "sta326", 0 }, - { "sta328", 0 }, - { "sta329", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id); - -static struct i2c_driver sta32x_i2c_driver = { - .driver = { - .name = "sta32x", - .owner = THIS_MODULE, - }, - .probe = sta32x_i2c_probe, - .remove = __devexit_p(sta32x_i2c_remove), - .id_table = sta32x_i2c_id, -}; - -static int __init sta32x_init(void) -{ - return i2c_add_driver(&sta32x_i2c_driver); -} -module_init(sta32x_init); - -static void __exit sta32x_exit(void) -{ - i2c_del_driver(&sta32x_i2c_driver); -} -module_exit(sta32x_exit); - -MODULE_DESCRIPTION("ASoC STA32X driver"); -MODULE_AUTHOR("Johannes Stezenbach "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/sta32x.h b/trunk/sound/soc/codecs/sta32x.h deleted file mode 100644 index b97ee5a75667..000000000000 --- a/trunk/sound/soc/codecs/sta32x.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system - * - * Copyright: 2011 Raumfeld GmbH - * Author: Johannes Stezenbach - * - * based on code from: - * Wolfson Microelectronics PLC. - * Mark Brown - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#ifndef _ASOC_STA_32X_H -#define _ASOC_STA_32X_H - -/* STA326 register addresses */ - -#define STA32X_REGISTER_COUNT 0x2d - -#define STA32X_CONFA 0x00 -#define STA32X_CONFB 0x01 -#define STA32X_CONFC 0x02 -#define STA32X_CONFD 0x03 -#define STA32X_CONFE 0x04 -#define STA32X_CONFF 0x05 -#define STA32X_MMUTE 0x06 -#define STA32X_MVOL 0x07 -#define STA32X_C1VOL 0x08 -#define STA32X_C2VOL 0x09 -#define STA32X_C3VOL 0x0a -#define STA32X_AUTO1 0x0b -#define STA32X_AUTO2 0x0c -#define STA32X_AUTO3 0x0d -#define STA32X_C1CFG 0x0e -#define STA32X_C2CFG 0x0f -#define STA32X_C3CFG 0x10 -#define STA32X_TONE 0x11 -#define STA32X_L1AR 0x12 -#define STA32X_L1ATRT 0x13 -#define STA32X_L2AR 0x14 -#define STA32X_L2ATRT 0x15 -#define STA32X_CFADDR2 0x16 -#define STA32X_B1CF1 0x17 -#define STA32X_B1CF2 0x18 -#define STA32X_B1CF3 0x19 -#define STA32X_B2CF1 0x1a -#define STA32X_B2CF2 0x1b -#define STA32X_B2CF3 0x1c -#define STA32X_A1CF1 0x1d -#define STA32X_A1CF2 0x1e -#define STA32X_A1CF3 0x1f -#define STA32X_A2CF1 0x20 -#define STA32X_A2CF2 0x21 -#define STA32X_A2CF3 0x22 -#define STA32X_B0CF1 0x23 -#define STA32X_B0CF2 0x24 -#define STA32X_B0CF3 0x25 -#define STA32X_CFUD 0x26 -#define STA32X_MPCC1 0x27 -#define STA32X_MPCC2 0x28 -/* Reserved 0x29 */ -/* Reserved 0x2a */ -#define STA32X_Reserved 0x2a -#define STA32X_FDRC1 0x2b -#define STA32X_FDRC2 0x2c -/* Reserved 0x2d */ - - -/* STA326 register field definitions */ - -/* 0x00 CONFA */ -#define STA32X_CONFA_MCS_MASK 0x03 -#define STA32X_CONFA_MCS_SHIFT 0 -#define STA32X_CONFA_IR_MASK 0x18 -#define STA32X_CONFA_IR_SHIFT 3 -#define STA32X_CONFA_TWRB 0x20 -#define STA32X_CONFA_TWAB 0x40 -#define STA32X_CONFA_FDRB 0x80 - -/* 0x01 CONFB */ -#define STA32X_CONFB_SAI_MASK 0x0f -#define STA32X_CONFB_SAI_SHIFT 0 -#define STA32X_CONFB_SAIFB 0x10 -#define STA32X_CONFB_DSCKE 0x20 -#define STA32X_CONFB_C1IM 0x40 -#define STA32X_CONFB_C2IM 0x80 - -/* 0x02 CONFC */ -#define STA32X_CONFC_OM_MASK 0x03 -#define STA32X_CONFC_OM_SHIFT 0 -#define STA32X_CONFC_CSZ_MASK 0x7c -#define STA32X_CONFC_CSZ_SHIFT 2 - -/* 0x03 CONFD */ -#define STA32X_CONFD_HPB 0x01 -#define STA32X_CONFD_HPB_SHIFT 0 -#define STA32X_CONFD_DEMP 0x02 -#define STA32X_CONFD_DEMP_SHIFT 1 -#define STA32X_CONFD_DSPB 0x04 -#define STA32X_CONFD_DSPB_SHIFT 2 -#define STA32X_CONFD_PSL 0x08 -#define STA32X_CONFD_PSL_SHIFT 3 -#define STA32X_CONFD_BQL 0x10 -#define STA32X_CONFD_BQL_SHIFT 4 -#define STA32X_CONFD_DRC 0x20 -#define STA32X_CONFD_DRC_SHIFT 5 -#define STA32X_CONFD_ZDE 0x40 -#define STA32X_CONFD_ZDE_SHIFT 6 -#define STA32X_CONFD_MME 0x80 -#define STA32X_CONFD_MME_SHIFT 7 - -/* 0x04 CONFE */ -#define STA32X_CONFE_MPCV 0x01 -#define STA32X_CONFE_MPCV_SHIFT 0 -#define STA32X_CONFE_MPC 0x02 -#define STA32X_CONFE_MPC_SHIFT 1 -#define STA32X_CONFE_AME 0x08 -#define STA32X_CONFE_AME_SHIFT 3 -#define STA32X_CONFE_PWMS 0x10 -#define STA32X_CONFE_PWMS_SHIFT 4 -#define STA32X_CONFE_ZCE 0x40 -#define STA32X_CONFE_ZCE_SHIFT 6 -#define STA32X_CONFE_SVE 0x80 -#define STA32X_CONFE_SVE_SHIFT 7 - -/* 0x05 CONFF */ -#define STA32X_CONFF_OCFG_MASK 0x03 -#define STA32X_CONFF_OCFG_SHIFT 0 -#define STA32X_CONFF_IDE 0x04 -#define STA32X_CONFF_IDE_SHIFT 3 -#define STA32X_CONFF_BCLE 0x08 -#define STA32X_CONFF_ECLE 0x20 -#define STA32X_CONFF_PWDN 0x40 -#define STA32X_CONFF_EAPD 0x80 - -/* 0x06 MMUTE */ -#define STA32X_MMUTE_MMUTE 0x01 - -/* 0x0b AUTO1 */ -#define STA32X_AUTO1_AMEQ_MASK 0x03 -#define STA32X_AUTO1_AMEQ_SHIFT 0 -#define STA32X_AUTO1_AMV_MASK 0xc0 -#define STA32X_AUTO1_AMV_SHIFT 2 -#define STA32X_AUTO1_AMGC_MASK 0x30 -#define STA32X_AUTO1_AMGC_SHIFT 4 -#define STA32X_AUTO1_AMPS 0x80 - -/* 0x0c AUTO2 */ -#define STA32X_AUTO2_AMAME 0x01 -#define STA32X_AUTO2_AMAM_MASK 0x0e -#define STA32X_AUTO2_AMAM_SHIFT 1 -#define STA32X_AUTO2_XO_MASK 0xf0 -#define STA32X_AUTO2_XO_SHIFT 4 - -/* 0x0d AUTO3 */ -#define STA32X_AUTO3_PEQ_MASK 0x1f -#define STA32X_AUTO3_PEQ_SHIFT 0 - -/* 0x0e 0x0f 0x10 CxCFG */ -#define STA32X_CxCFG_TCB 0x01 /* only C1 and C2 */ -#define STA32X_CxCFG_TCB_SHIFT 0 -#define STA32X_CxCFG_EQBP 0x02 /* only C1 and C2 */ -#define STA32X_CxCFG_EQBP_SHIFT 1 -#define STA32X_CxCFG_VBP 0x03 -#define STA32X_CxCFG_VBP_SHIFT 2 -#define STA32X_CxCFG_BO 0x04 -#define STA32X_CxCFG_LS_MASK 0x30 -#define STA32X_CxCFG_LS_SHIFT 4 -#define STA32X_CxCFG_OM_MASK 0xc0 -#define STA32X_CxCFG_OM_SHIFT 6 - -/* 0x11 TONE */ -#define STA32X_TONE_BTC_SHIFT 0 -#define STA32X_TONE_TTC_SHIFT 4 - -/* 0x12 0x13 0x14 0x15 limiter attack/release */ -#define STA32X_LxA_SHIFT 0 -#define STA32X_LxR_SHIFT 4 - -/* 0x26 CFUD */ -#define STA32X_CFUD_W1 0x01 -#define STA32X_CFUD_WA 0x02 -#define STA32X_CFUD_R1 0x04 -#define STA32X_CFUD_RA 0x08 - - -/* biquad filter coefficient table offsets */ -#define STA32X_C1_BQ_BASE 0 -#define STA32X_C2_BQ_BASE 20 -#define STA32X_CH_BQ_NUM 4 -#define STA32X_BQ_NUM_COEF 5 -#define STA32X_XO_HP_BQ_BASE 40 -#define STA32X_XO_LP_BQ_BASE 45 -#define STA32X_C1_PRESCALE 50 -#define STA32X_C2_PRESCALE 51 -#define STA32X_C1_POSTSCALE 52 -#define STA32X_C2_POSTSCALE 53 -#define STA32X_C3_POSTSCALE 54 -#define STA32X_TW_POSTSCALE 55 -#define STA32X_C1_MIX1 56 -#define STA32X_C1_MIX2 57 -#define STA32X_C2_MIX1 58 -#define STA32X_C2_MIX2 59 -#define STA32X_C3_MIX1 60 -#define STA32X_C3_MIX2 61 - -#endif /* _ASOC_STA_32X_H */ diff --git a/trunk/sound/soc/codecs/tlv320aic3x.c b/trunk/sound/soc/codecs/tlv320aic3x.c index 0963c4c7a83f..789453d44ec5 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.c +++ b/trunk/sound/soc/codecs/tlv320aic3x.c @@ -226,13 +226,11 @@ static const char *aic3x_adc_hpf[] = #define RDAC_ENUM 1 #define LHPCOM_ENUM 2 #define RHPCOM_ENUM 3 -#define LINE1L_2_L_ENUM 4 -#define LINE1L_2_R_ENUM 5 -#define LINE1R_2_L_ENUM 6 -#define LINE1R_2_R_ENUM 7 -#define LINE2L_ENUM 8 -#define LINE2R_ENUM 9 -#define ADC_HPF_ENUM 10 +#define LINE1L_ENUM 4 +#define LINE1R_ENUM 5 +#define LINE2L_ENUM 6 +#define LINE2R_ENUM 7 +#define ADC_HPF_ENUM 8 static const struct soc_enum aic3x_enum[] = { SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), @@ -240,8 +238,6 @@ static const struct soc_enum aic3x_enum[] = { SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux), SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux), SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_SINGLE(LINE1L_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_SINGLE(LINE1R_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), @@ -494,16 +490,12 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { }; /* Left Line1 Mux */ -static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_L_ENUM]); -static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_R_ENUM]); +static const struct snd_kcontrol_new aic3x_left_line1_mux_controls = +SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_ENUM]); /* Right Line1 Mux */ -static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_R_ENUM]); -static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_L_ENUM]); +static const struct snd_kcontrol_new aic3x_right_line1_mux_controls = +SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_ENUM]); /* Left Line2 Mux */ static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = @@ -543,9 +535,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { &aic3x_left_pga_mixer_controls[0], ARRAY_SIZE(aic3x_left_pga_mixer_controls)), SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, - &aic3x_left_line1l_mux_controls), + &aic3x_left_line1_mux_controls), SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0, - &aic3x_left_line1r_mux_controls), + &aic3x_left_line1_mux_controls), SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line2_mux_controls), @@ -556,9 +548,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { &aic3x_right_pga_mixer_controls[0], ARRAY_SIZE(aic3x_right_pga_mixer_controls)), SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0, - &aic3x_right_line1l_mux_controls), + &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, - &aic3x_right_line1r_mux_controls), + &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line2_mux_controls), diff --git a/trunk/sound/soc/codecs/twl6040.c b/trunk/sound/soc/codecs/twl6040.c index cd63bba623df..4c336636d4f5 100644 --- a/trunk/sound/soc/codecs/twl6040.c +++ b/trunk/sound/soc/codecs/twl6040.c @@ -954,9 +954,9 @@ static DECLARE_TLV_DB_SCALE(mic_preamp_tlv, -600, 600, 0); /* * MICGAIN volume control: - * from 6 to 30 dB in 6 dB steps + * from -6 to 30 dB in 6 dB steps */ -static DECLARE_TLV_DB_SCALE(mic_amp_tlv, 600, 600, 0); +static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0); /* * AFMGAIN volume control: diff --git a/trunk/sound/soc/codecs/wm8782.c b/trunk/sound/soc/codecs/wm8782.c deleted file mode 100644 index a2a09f85ea99..000000000000 --- a/trunk/sound/soc/codecs/wm8782.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * sound/soc/codecs/wm8782.c - * simple, strap-pin configured 24bit 2ch ADC - * - * Copyright: 2011 Raumfeld GmbH - * Author: Johannes Stezenbach - * - * based on ad73311.c - * Copyright: Analog Device Inc. - * Author: Cliff Cai - * - * This program is free software; 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct snd_soc_dai_driver wm8782_dai = { - .name = "wm8782", - .capture = { - .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, - /* For configurations with FSAMPEN=0 */ - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S20_3LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, -}; - -static struct snd_soc_codec_driver soc_codec_dev_wm8782; - -static __devinit int wm8782_probe(struct platform_device *pdev) -{ - return snd_soc_register_codec(&pdev->dev, - &soc_codec_dev_wm8782, &wm8782_dai, 1); -} - -static int __devexit wm8782_remove(struct platform_device *pdev) -{ - snd_soc_unregister_codec(&pdev->dev); - return 0; -} - -static struct platform_driver wm8782_codec_driver = { - .driver = { - .name = "wm8782", - .owner = THIS_MODULE, - }, - .probe = wm8782_probe, - .remove = wm8782_remove, -}; - -static int __init wm8782_init(void) -{ - return platform_driver_register(&wm8782_codec_driver); -} -module_init(wm8782_init); - -static void __exit wm8782_exit(void) -{ - platform_driver_unregister(&wm8782_codec_driver); -} -module_exit(wm8782_exit); - -MODULE_DESCRIPTION("ASoC WM8782 driver"); -MODULE_AUTHOR("Johannes Stezenbach "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/wm8900.c b/trunk/sound/soc/codecs/wm8900.c index 082040eda8a2..449ea09a193d 100644 --- a/trunk/sound/soc/codecs/wm8900.c +++ b/trunk/sound/soc/codecs/wm8900.c @@ -1167,7 +1167,6 @@ static int wm8900_resume(struct snd_soc_codec *codec) ret = wm8900_set_fll(codec, 0, fll_in, fll_out); if (ret != 0) { dev_err(codec->dev, "Failed to restart FLL\n"); - kfree(cache); return ret; } } diff --git a/trunk/sound/soc/codecs/wm8904.c b/trunk/sound/soc/codecs/wm8904.c index b085575d4aa5..9b3bba4df5b3 100644 --- a/trunk/sound/soc/codecs/wm8904.c +++ b/trunk/sound/soc/codecs/wm8904.c @@ -2560,7 +2560,6 @@ static __devexit int wm8904_i2c_remove(struct i2c_client *client) static const struct i2c_device_id wm8904_i2c_id[] = { { "wm8904", WM8904 }, { "wm8912", WM8912 }, - { "wm8918", WM8904 }, /* Actually a subset, updates to follow */ { } }; MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id); diff --git a/trunk/sound/soc/codecs/wm8915.c b/trunk/sound/soc/codecs/wm8915.c index 423baa9be241..e2ab4fac2819 100644 --- a/trunk/sound/soc/codecs/wm8915.c +++ b/trunk/sound/soc/codecs/wm8915.c @@ -41,12 +41,14 @@ #define HPOUT2L 4 #define HPOUT2R 8 -#define WM8915_NUM_SUPPLIES 4 +#define WM8915_NUM_SUPPLIES 6 static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = { + "DCVDD", "DBVDD", "AVDD1", "AVDD2", "CPVDD", + "MICVDD", }; struct wm8915_priv { @@ -55,7 +57,6 @@ struct wm8915_priv { int ldo1ena; int sysclk; - int sysclk_src; int fll_src; int fll_fref; @@ -75,7 +76,6 @@ struct wm8915_priv { struct wm8915_pdata pdata; int rx_rate[WM8915_AIFS]; - int bclk_rate[WM8915_AIFS]; /* Platform dependant ReTune mobile configuration */ int num_retune_mobile_texts; @@ -113,6 +113,8 @@ 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, @@ -1563,50 +1565,6 @@ static int wm8915_reset(struct snd_soc_codec *codec) return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915); } -static const int bclk_divs[] = { - 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 -}; - -static void wm8915_update_bclk(struct snd_soc_codec *codec) -{ - struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); - int aif, best, cur_val, bclk_rate, bclk_reg, i; - - /* Don't bother if we're in a low frequency idle mode that - * can't support audio. - */ - if (wm8915->sysclk < 64000) - return; - - for (aif = 0; aif < WM8915_AIFS; aif++) { - switch (aif) { - case 0: - bclk_reg = WM8915_AIF1_BCLK; - break; - case 1: - bclk_reg = WM8915_AIF2_BCLK; - break; - } - - bclk_rate = wm8915->bclk_rate[aif]; - - /* 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(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", - bclk_divs[best], bclk_rate); - - snd_soc_update_bits(codec, bclk_reg, - WM8915_AIF1_BCLK_DIV_MASK, best); - } -} - static int wm8915_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -1759,6 +1717,10 @@ static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 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 }; @@ -1769,11 +1731,17 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); - int bits, i, bclk_rate; + int bits, i, bclk_rate, best, cur_val; int aifdata = 0; + int bclk = 0; int lrclk = 0; int dsp = 0; - int aifdata_reg, lrclk_reg, dsp_shift; + 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: @@ -1785,6 +1753,7 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, 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: @@ -1796,6 +1765,7 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, 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: @@ -1809,9 +1779,6 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, return bclk_rate; } - wm8915->bclk_rate[dai->id] = bclk_rate; - wm8915->rx_rate[dai->id] = params_rate(params); - /* Needs looking at for TDM */ bits = snd_pcm_format_width(params_format(params)); if (bits < 0) @@ -1829,7 +1796,18 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, } dsp |= i << dsp_shift; - wm8915_update_bclk(codec); + /* 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", @@ -1839,11 +1817,14 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, 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; } @@ -1857,9 +1838,6 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, int src; int old; - if (freq == wm8915->sysclk && clk_id == wm8915->sysclk_src) - return 0; - /* Disable SYSCLK while we reconfigure */ old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA; snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, @@ -1904,8 +1882,6 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, return -EINVAL; } - wm8915_update_bclk(codec); - snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK, src << WM8915_SYSCLK_SRC_SHIFT | ratediv); @@ -1913,8 +1889,6 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, WM8915_SYSCLK_ENA, old); - wm8915->sysclk_src = clk_id; - return 0; } @@ -2033,7 +2007,6 @@ 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 i2c_client *i2c = to_i2c_client(codec->dev); struct _fll_div fll_div; unsigned long timeout; int ret, reg; @@ -2120,18 +2093,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, else timeout = msecs_to_jiffies(2); - /* Allow substantially longer if we've actually got the IRQ */ - if (i2c->irq) - timeout *= 1000; - - ret = wait_for_completion_timeout(&wm8915->fll_lock, timeout); - - if (ret == 0 && i2c->irq) { - dev_err(codec->dev, "Timed out waiting for FLL\n"); - ret = -ETIMEDOUT; - } else { - ret = 0; - } + wait_for_completion_timeout(&wm8915->fll_lock, timeout); dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); @@ -2139,7 +2101,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, wm8915->fll_fout = Fout; wm8915->fll_src = source; - return ret; + return 0; } #ifdef CONFIG_GPIOLIB @@ -2331,12 +2293,6 @@ static void wm8915_micd(struct snd_soc_codec *codec) SND_JACK_HEADSET | SND_JACK_BTN_0); wm8915->jack_mic = true; wm8915->detecting = false; - - /* Increase poll rate to give better responsiveness - * for buttons */ - snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, - WM8915_MICD_RATE_MASK, - 5 << WM8915_MICD_RATE_SHIFT); } /* If we detected a lower impedence during initial startup @@ -2377,17 +2333,15 @@ static void wm8915_micd(struct snd_soc_codec *codec) SND_JACK_HEADPHONE, SND_JACK_HEADSET | SND_JACK_BTN_0); - - /* Increase the detection rate a bit for - * responsiveness. - */ - snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, - WM8915_MICD_RATE_MASK, - 7 << WM8915_MICD_RATE_SHIFT); - 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) @@ -2429,20 +2383,6 @@ static irqreturn_t wm8915_irq(int irq, void *data) } } -static irqreturn_t wm8915_edge_irq(int irq, void *data) -{ - irqreturn_t ret = IRQ_NONE; - irqreturn_t val; - - do { - val = wm8915_irq(irq, data); - if (val != IRQ_NONE) - ret = val; - } while (val != IRQ_NONE); - - return ret; -} - static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec) { struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); @@ -2542,6 +2482,8 @@ static int wm8915_probe(struct snd_soc_codec *codec) 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++) { @@ -2767,14 +2709,8 @@ static int wm8915_probe(struct snd_soc_codec *codec) irq_flags |= IRQF_ONESHOT; - if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) - ret = request_threaded_irq(i2c->irq, NULL, - wm8915_edge_irq, - irq_flags, "wm8915", codec); - else - ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq, - irq_flags, "wm8915", codec); - + 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, diff --git a/trunk/sound/soc/codecs/wm8940.c b/trunk/sound/soc/codecs/wm8940.c index 056daa0010f9..25580e3ee7c4 100644 --- a/trunk/sound/soc/codecs/wm8940.c +++ b/trunk/sound/soc/codecs/wm8940.c @@ -297,6 +297,8 @@ static int wm8940_add_widgets(struct snd_soc_codec *codec) if (ret) goto error_ret; ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); + if (ret) + goto error_ret; error_ret: return ret; @@ -681,6 +683,8 @@ static int wm8940_resume(struct snd_soc_codec *codec) } } ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + if (ret) + goto error_ret; error_ret: return ret; @@ -726,6 +730,9 @@ static int wm8940_probe(struct snd_soc_codec *codec) if (ret) return ret; ret = wm8940_add_widgets(codec); + if (ret) + return ret; + return ret; } diff --git a/trunk/sound/soc/codecs/wm8962.c b/trunk/sound/soc/codecs/wm8962.c index 8499c563a9b5..5e05eed96c38 100644 --- a/trunk/sound/soc/codecs/wm8962.c +++ b/trunk/sound/soc/codecs/wm8962.c @@ -78,8 +78,6 @@ struct wm8962_priv { #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; #endif - - int irq; }; /* We can't use the same notifier block for more than one supply and @@ -1984,7 +1982,6 @@ static const unsigned int classd_tlv[] = { 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0), 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0), }; -static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); /* The VU bits for the headphones are in a different register to the mute * bits and only take effect on the PGA if it is actually powered. @@ -2122,18 +2119,6 @@ SOC_SINGLE_TLV("HPMIXR MIXINR Volume", WM8962_HEADPHONE_MIXER_4, SOC_SINGLE_TLV("Speaker Boost Volume", WM8962_CLASS_D_CONTROL_2, 0, 7, 0, classd_tlv), - -SOC_SINGLE("EQ Switch", WM8962_EQ1, WM8962_EQ_ENA_SHIFT, 1, 0), -SOC_DOUBLE_R_TLV("EQ1 Volume", WM8962_EQ2, WM8962_EQ22, - WM8962_EQL_B1_GAIN_SHIFT, 31, 0, eq_tlv), -SOC_DOUBLE_R_TLV("EQ2 Volume", WM8962_EQ2, WM8962_EQ22, - WM8962_EQL_B2_GAIN_SHIFT, 31, 0, eq_tlv), -SOC_DOUBLE_R_TLV("EQ3 Volume", WM8962_EQ2, WM8962_EQ22, - WM8962_EQL_B3_GAIN_SHIFT, 31, 0, eq_tlv), -SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23, - WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv), -SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23, - WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv), }; static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = { @@ -2199,8 +2184,6 @@ static int sysclk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - unsigned long timeout; int src; int fll; @@ -2220,19 +2203,9 @@ static int sysclk_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - if (fll) { + if (fll) snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, WM8962_FLL_ENA); - if (wm8962->irq) { - timeout = msecs_to_jiffies(5); - timeout = wait_for_completion_timeout(&wm8962->fll_lock, - timeout); - - if (timeout == 0) - dev_err(codec->dev, - "Timed out starting FLL\n"); - } - } break; case SND_SOC_DAPM_POST_PMD: @@ -2790,44 +2763,18 @@ static const int bclk_divs[] = { 1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32 }; -static const int sysclk_rates[] = { - 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, -}; - static void wm8962_configure_bclk(struct snd_soc_codec *codec) { struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); int dspclk, i; int clocking2 = 0; - int clocking4 = 0; int aif2 = 0; - if (!wm8962->sysclk_rate) { - dev_dbg(codec->dev, "No SYSCLK configured\n"); - return; - } - - if (!wm8962->bclk || !wm8962->lrclk) { - dev_dbg(codec->dev, "No audio clocks configured\n"); + if (!wm8962->bclk) { + dev_dbg(codec->dev, "No BCLK rate configured\n"); return; } - for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) { - if (sysclk_rates[i] == wm8962->sysclk_rate / wm8962->lrclk) { - clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT; - break; - } - } - - if (i == ARRAY_SIZE(sysclk_rates)) { - dev_err(codec->dev, "Unsupported sysclk ratio %d\n", - wm8962->sysclk_rate / wm8962->lrclk); - return; - } - - snd_soc_update_bits(codec, WM8962_CLOCKING_4, - WM8962_SYSCLK_RATE_MASK, clocking4); - dspclk = snd_soc_read(codec, WM8962_CLOCKING1); if (dspclk < 0) { dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk); @@ -2897,8 +2844,6 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, /* VMID 2*50k */ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, WM8962_VMID_SEL_MASK, 0x80); - - wm8962_configure_bclk(codec); break; case SND_SOC_BIAS_STANDBY: @@ -2931,6 +2876,8 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_CLKREG_OVD, WM8962_CLKREG_OVD); + + wm8962_configure_bclk(codec); } /* VMID 2*250k */ @@ -2971,6 +2918,10 @@ static const struct { { 96000, 6 }, }; +static const int sysclk_rates[] = { + 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, +}; + static int wm8962_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -2978,27 +2929,41 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + int rate = params_rate(params); int i; int aif0 = 0; int adctl3 = 0; + int clocking4 = 0; wm8962->bclk = snd_soc_params_to_bclk(params); wm8962->lrclk = params_rate(params); for (i = 0; i < ARRAY_SIZE(sr_vals); i++) { - if (sr_vals[i].rate == wm8962->lrclk) { + if (sr_vals[i].rate == rate) { adctl3 |= sr_vals[i].reg; break; } } if (i == ARRAY_SIZE(sr_vals)) { - dev_err(codec->dev, "Unsupported rate %dHz\n", wm8962->lrclk); + dev_err(codec->dev, "Unsupported rate %dHz\n", rate); return -EINVAL; } - if (wm8962->lrclk % 8000 == 0) + if (rate % 8000 == 0) adctl3 |= WM8962_SAMPLE_RATE_INT_MODE; + for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) { + if (sysclk_rates[i] == wm8962->sysclk_rate / rate) { + clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT; + break; + } + } + if (i == ARRAY_SIZE(sysclk_rates)) { + dev_err(codec->dev, "Unsupported sysclk ratio %d\n", + wm8962->sysclk_rate / rate); + return -EINVAL; + } + switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; @@ -3020,6 +2985,8 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3, WM8962_SAMPLE_RATE_INT_MODE | WM8962_SAMPLE_RATE_MASK, adctl3); + snd_soc_update_bits(codec, WM8962_CLOCKING_4, + WM8962_SYSCLK_RATE_MASK, clocking4); wm8962_configure_bclk(codec); @@ -3294,31 +3261,16 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); - ret = 0; - - if (fll1 & WM8962_FLL_ENA) { - /* This should be a massive overestimate but go even - * higher if we'll error out - */ - if (wm8962->irq) - timeout = msecs_to_jiffies(5); - else - timeout = msecs_to_jiffies(1); - - timeout = wait_for_completion_timeout(&wm8962->fll_lock, - timeout); + /* This should be a massive overestimate */ + timeout = msecs_to_jiffies(1); - if (timeout == 0 && wm8962->irq) { - dev_err(codec->dev, "FLL lock timed out"); - ret = -ETIMEDOUT; - } - } + wait_for_completion_timeout(&wm8962->fll_lock, timeout); wm8962->fll_fref = Fref; wm8962->fll_fout = Fout; wm8962->fll_src = source; - return ret; + return 0; } static int wm8962_mute(struct snd_soc_dai *dai, int mute) @@ -3779,6 +3731,8 @@ static int wm8962_probe(struct snd_soc_codec *codec) int ret; struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); + struct i2c_client *i2c = container_of(codec->dev, struct i2c_client, + dev); u16 *reg_cache = codec->reg_cache; int i, trigger, irq_pol; bool dmicclk, dmicdat; @@ -3917,9 +3871,6 @@ static int wm8962_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME, WM8962_HPOUT_VU, WM8962_HPOUT_VU); - /* Stereo control for EQ */ - snd_soc_update_bits(codec, WM8962_EQ1, WM8962_EQ_SHARED_COEFF, 0); - wm8962_add_widgets(codec); /* Save boards having to disable DMIC when not in use */ @@ -3948,7 +3899,7 @@ static int wm8962_probe(struct snd_soc_codec *codec) wm8962_init_beep(codec); wm8962_init_gpio(codec); - if (wm8962->irq) { + if (i2c->irq) { if (pdata && pdata->irq_active_low) { trigger = IRQF_TRIGGER_LOW; irq_pol = WM8962_IRQ_POL; @@ -3960,13 +3911,12 @@ static int wm8962_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL, WM8962_IRQ_POL, irq_pol); - ret = request_threaded_irq(wm8962->irq, NULL, wm8962_irq, + ret = request_threaded_irq(i2c->irq, NULL, wm8962_irq, trigger | IRQF_ONESHOT, "wm8962", codec); if (ret != 0) { dev_err(codec->dev, "Failed to request IRQ %d: %d\n", - wm8962->irq, ret); - wm8962->irq = 0; + i2c->irq, ret); /* Non-fatal */ } else { /* Enable some IRQs by default */ @@ -3991,10 +3941,12 @@ static int wm8962_probe(struct snd_soc_codec *codec) static int wm8962_remove(struct snd_soc_codec *codec) { struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct i2c_client *i2c = container_of(codec->dev, struct i2c_client, + dev); int i; - if (wm8962->irq) - free_irq(wm8962->irq, codec); + if (i2c->irq) + free_irq(i2c->irq, codec); cancel_delayed_work_sync(&wm8962->mic_work); @@ -4034,8 +3986,6 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8962); - wm8962->irq = i2c->irq; - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8962, &wm8962_dai, 1); if (ret < 0) diff --git a/trunk/sound/soc/codecs/wm8983.c b/trunk/sound/soc/codecs/wm8983.c deleted file mode 100644 index 17f04ec2b940..000000000000 --- a/trunk/sound/soc/codecs/wm8983.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* - * wm8983.c -- WM8983 ALSA SoC Audio driver - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Dimitris Papastamos - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wm8983.h" - -static const u16 wm8983_reg_defs[WM8983_MAX_REGISTER + 1] = { - [0x00] = 0x0000, /* R0 - Software Reset */ - [0x01] = 0x0000, /* R1 - Power management 1 */ - [0x02] = 0x0000, /* R2 - Power management 2 */ - [0x03] = 0x0000, /* R3 - Power management 3 */ - [0x04] = 0x0050, /* R4 - Audio Interface */ - [0x05] = 0x0000, /* R5 - Companding control */ - [0x06] = 0x0140, /* R6 - Clock Gen control */ - [0x07] = 0x0000, /* R7 - Additional control */ - [0x08] = 0x0000, /* R8 - GPIO Control */ - [0x09] = 0x0000, /* R9 - Jack Detect Control 1 */ - [0x0A] = 0x0000, /* R10 - DAC Control */ - [0x0B] = 0x00FF, /* R11 - Left DAC digital Vol */ - [0x0C] = 0x00FF, /* R12 - Right DAC digital vol */ - [0x0D] = 0x0000, /* R13 - Jack Detect Control 2 */ - [0x0E] = 0x0100, /* R14 - ADC Control */ - [0x0F] = 0x00FF, /* R15 - Left ADC Digital Vol */ - [0x10] = 0x00FF, /* R16 - Right ADC Digital Vol */ - [0x12] = 0x012C, /* R18 - EQ1 - low shelf */ - [0x13] = 0x002C, /* R19 - EQ2 - peak 1 */ - [0x14] = 0x002C, /* R20 - EQ3 - peak 2 */ - [0x15] = 0x002C, /* R21 - EQ4 - peak 3 */ - [0x16] = 0x002C, /* R22 - EQ5 - high shelf */ - [0x18] = 0x0032, /* R24 - DAC Limiter 1 */ - [0x19] = 0x0000, /* R25 - DAC Limiter 2 */ - [0x1B] = 0x0000, /* R27 - Notch Filter 1 */ - [0x1C] = 0x0000, /* R28 - Notch Filter 2 */ - [0x1D] = 0x0000, /* R29 - Notch Filter 3 */ - [0x1E] = 0x0000, /* R30 - Notch Filter 4 */ - [0x20] = 0x0038, /* R32 - ALC control 1 */ - [0x21] = 0x000B, /* R33 - ALC control 2 */ - [0x22] = 0x0032, /* R34 - ALC control 3 */ - [0x23] = 0x0000, /* R35 - Noise Gate */ - [0x24] = 0x0008, /* R36 - PLL N */ - [0x25] = 0x000C, /* R37 - PLL K 1 */ - [0x26] = 0x0093, /* R38 - PLL K 2 */ - [0x27] = 0x00E9, /* R39 - PLL K 3 */ - [0x29] = 0x0000, /* R41 - 3D control */ - [0x2A] = 0x0000, /* R42 - OUT4 to ADC */ - [0x2B] = 0x0000, /* R43 - Beep control */ - [0x2C] = 0x0033, /* R44 - Input ctrl */ - [0x2D] = 0x0010, /* R45 - Left INP PGA gain ctrl */ - [0x2E] = 0x0010, /* R46 - Right INP PGA gain ctrl */ - [0x2F] = 0x0100, /* R47 - Left ADC BOOST ctrl */ - [0x30] = 0x0100, /* R48 - Right ADC BOOST ctrl */ - [0x31] = 0x0002, /* R49 - Output ctrl */ - [0x32] = 0x0001, /* R50 - Left mixer ctrl */ - [0x33] = 0x0001, /* R51 - Right mixer ctrl */ - [0x34] = 0x0039, /* R52 - LOUT1 (HP) volume ctrl */ - [0x35] = 0x0039, /* R53 - ROUT1 (HP) volume ctrl */ - [0x36] = 0x0039, /* R54 - LOUT2 (SPK) volume ctrl */ - [0x37] = 0x0039, /* R55 - ROUT2 (SPK) volume ctrl */ - [0x38] = 0x0001, /* R56 - OUT3 mixer ctrl */ - [0x39] = 0x0001, /* R57 - OUT4 (MONO) mix ctrl */ - [0x3D] = 0x0000 /* R61 - BIAS CTRL */ -}; - -static const struct wm8983_reg_access { - u16 read; /* Mask of readable bits */ - u16 write; /* Mask of writable bits */ -} wm8983_access_masks[WM8983_MAX_REGISTER + 1] = { - [0x00] = { 0x0000, 0x01FF }, /* R0 - Software Reset */ - [0x01] = { 0x0000, 0x01FF }, /* R1 - Power management 1 */ - [0x02] = { 0x0000, 0x01FF }, /* R2 - Power management 2 */ - [0x03] = { 0x0000, 0x01EF }, /* R3 - Power management 3 */ - [0x04] = { 0x0000, 0x01FF }, /* R4 - Audio Interface */ - [0x05] = { 0x0000, 0x003F }, /* R5 - Companding control */ - [0x06] = { 0x0000, 0x01FD }, /* R6 - Clock Gen control */ - [0x07] = { 0x0000, 0x000F }, /* R7 - Additional control */ - [0x08] = { 0x0000, 0x003F }, /* R8 - GPIO Control */ - [0x09] = { 0x0000, 0x0070 }, /* R9 - Jack Detect Control 1 */ - [0x0A] = { 0x0000, 0x004F }, /* R10 - DAC Control */ - [0x0B] = { 0x0000, 0x01FF }, /* R11 - Left DAC digital Vol */ - [0x0C] = { 0x0000, 0x01FF }, /* R12 - Right DAC digital vol */ - [0x0D] = { 0x0000, 0x00FF }, /* R13 - Jack Detect Control 2 */ - [0x0E] = { 0x0000, 0x01FB }, /* R14 - ADC Control */ - [0x0F] = { 0x0000, 0x01FF }, /* R15 - Left ADC Digital Vol */ - [0x10] = { 0x0000, 0x01FF }, /* R16 - Right ADC Digital Vol */ - [0x12] = { 0x0000, 0x017F }, /* R18 - EQ1 - low shelf */ - [0x13] = { 0x0000, 0x017F }, /* R19 - EQ2 - peak 1 */ - [0x14] = { 0x0000, 0x017F }, /* R20 - EQ3 - peak 2 */ - [0x15] = { 0x0000, 0x017F }, /* R21 - EQ4 - peak 3 */ - [0x16] = { 0x0000, 0x007F }, /* R22 - EQ5 - high shelf */ - [0x18] = { 0x0000, 0x01FF }, /* R24 - DAC Limiter 1 */ - [0x19] = { 0x0000, 0x007F }, /* R25 - DAC Limiter 2 */ - [0x1B] = { 0x0000, 0x01FF }, /* R27 - Notch Filter 1 */ - [0x1C] = { 0x0000, 0x017F }, /* R28 - Notch Filter 2 */ - [0x1D] = { 0x0000, 0x017F }, /* R29 - Notch Filter 3 */ - [0x1E] = { 0x0000, 0x017F }, /* R30 - Notch Filter 4 */ - [0x20] = { 0x0000, 0x01BF }, /* R32 - ALC control 1 */ - [0x21] = { 0x0000, 0x00FF }, /* R33 - ALC control 2 */ - [0x22] = { 0x0000, 0x01FF }, /* R34 - ALC control 3 */ - [0x23] = { 0x0000, 0x000F }, /* R35 - Noise Gate */ - [0x24] = { 0x0000, 0x001F }, /* R36 - PLL N */ - [0x25] = { 0x0000, 0x003F }, /* R37 - PLL K 1 */ - [0x26] = { 0x0000, 0x01FF }, /* R38 - PLL K 2 */ - [0x27] = { 0x0000, 0x01FF }, /* R39 - PLL K 3 */ - [0x29] = { 0x0000, 0x000F }, /* R41 - 3D control */ - [0x2A] = { 0x0000, 0x01E7 }, /* R42 - OUT4 to ADC */ - [0x2B] = { 0x0000, 0x01BF }, /* R43 - Beep control */ - [0x2C] = { 0x0000, 0x0177 }, /* R44 - Input ctrl */ - [0x2D] = { 0x0000, 0x01FF }, /* R45 - Left INP PGA gain ctrl */ - [0x2E] = { 0x0000, 0x01FF }, /* R46 - Right INP PGA gain ctrl */ - [0x2F] = { 0x0000, 0x0177 }, /* R47 - Left ADC BOOST ctrl */ - [0x30] = { 0x0000, 0x0177 }, /* R48 - Right ADC BOOST ctrl */ - [0x31] = { 0x0000, 0x007F }, /* R49 - Output ctrl */ - [0x32] = { 0x0000, 0x01FF }, /* R50 - Left mixer ctrl */ - [0x33] = { 0x0000, 0x01FF }, /* R51 - Right mixer ctrl */ - [0x34] = { 0x0000, 0x01FF }, /* R52 - LOUT1 (HP) volume ctrl */ - [0x35] = { 0x0000, 0x01FF }, /* R53 - ROUT1 (HP) volume ctrl */ - [0x36] = { 0x0000, 0x01FF }, /* R54 - LOUT2 (SPK) volume ctrl */ - [0x37] = { 0x0000, 0x01FF }, /* R55 - ROUT2 (SPK) volume ctrl */ - [0x38] = { 0x0000, 0x004F }, /* R56 - OUT3 mixer ctrl */ - [0x39] = { 0x0000, 0x00FF }, /* R57 - OUT4 (MONO) mix ctrl */ - [0x3D] = { 0x0000, 0x0100 } /* R61 - BIAS CTRL */ -}; - -/* vol/gain update regs */ -static const int vol_update_regs[] = { - WM8983_LEFT_DAC_DIGITAL_VOL, - WM8983_RIGHT_DAC_DIGITAL_VOL, - WM8983_LEFT_ADC_DIGITAL_VOL, - WM8983_RIGHT_ADC_DIGITAL_VOL, - WM8983_LOUT1_HP_VOLUME_CTRL, - WM8983_ROUT1_HP_VOLUME_CTRL, - WM8983_LOUT2_SPK_VOLUME_CTRL, - WM8983_ROUT2_SPK_VOLUME_CTRL, - WM8983_LEFT_INP_PGA_GAIN_CTRL, - WM8983_RIGHT_INP_PGA_GAIN_CTRL -}; - -struct wm8983_priv { - enum snd_soc_control_type control_type; - u32 sysclk; - u32 bclk; -}; - -static const struct { - int div; - int ratio; -} fs_ratios[] = { - { 10, 128 }, - { 15, 192 }, - { 20, 256 }, - { 30, 384 }, - { 40, 512 }, - { 60, 768 }, - { 80, 1024 }, - { 120, 1536 } -}; - -static const int srates[] = { 48000, 32000, 24000, 16000, 12000, 8000 }; - -static const int bclk_divs[] = { - 1, 2, 4, 8, 16, 32 -}; - -static int eqmode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -static int eqmode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - -static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); -static const DECLARE_TLV_DB_SCALE(adc_tlv, -12700, 50, 1); -static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); -static const DECLARE_TLV_DB_SCALE(lim_thresh_tlv, -600, 100, 0); -static const DECLARE_TLV_DB_SCALE(lim_boost_tlv, 0, 100, 0); -static const DECLARE_TLV_DB_SCALE(alc_min_tlv, -1200, 600, 0); -static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -675, 600, 0); -static const DECLARE_TLV_DB_SCALE(alc_tar_tlv, -2250, 150, 0); -static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1200, 75, 0); -static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1); -static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); -static const DECLARE_TLV_DB_SCALE(aux_tlv, -1500, 300, 0); -static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); -static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); - -static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; -static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, - alc_sel_text); - -static const char *alc_mode_text[] = { "ALC", "Limiter" }; -static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, - alc_mode_text); - -static const char *filter_mode_text[] = { "Audio", "Application" }; -static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7, - filter_mode_text); - -static const char *eq_bw_text[] = { "Narrow", "Wide" }; -static const char *eqmode_text[] = { "Capture", "Playback" }; -static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); - -static const char *eq1_cutoff_text[] = { - "80Hz", "105Hz", "135Hz", "175Hz" -}; -static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5, - eq1_cutoff_text); -static const char *eq2_cutoff_text[] = { - "230Hz", "300Hz", "385Hz", "500Hz" -}; -static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, - eq2_cutoff_text); -static const char *eq3_cutoff_text[] = { - "650Hz", "850Hz", "1.1kHz", "1.4kHz" -}; -static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, - eq3_cutoff_text); -static const char *eq4_cutoff_text[] = { - "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" -}; -static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, - eq4_cutoff_text); -static const char *eq5_cutoff_text[] = { - "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" -}; -static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, - eq5_cutoff_text); - -static const char *speaker_mode_text[] = { "Class A/B", "Class D" }; -static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text); - -static const char *depth_3d_text[] = { - "Off", - "6.67%", - "13.3%", - "20%", - "26.7%", - "33.3%", - "40%", - "46.6%", - "53.3%", - "60%", - "66.7%", - "73.3%", - "80%", - "86.7%", - "93.3%", - "100%" -}; -static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0, - depth_3d_text); - -static const struct snd_kcontrol_new wm8983_snd_controls[] = { - SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL, - 0, 1, 0), - - SOC_ENUM("ALC Capture Function", alc_sel), - SOC_SINGLE_TLV("ALC Capture Max Volume", WM8983_ALC_CONTROL_1, - 3, 7, 0, alc_max_tlv), - SOC_SINGLE_TLV("ALC Capture Min Volume", WM8983_ALC_CONTROL_1, - 0, 7, 0, alc_min_tlv), - SOC_SINGLE_TLV("ALC Capture Target Volume", WM8983_ALC_CONTROL_2, - 0, 15, 0, alc_tar_tlv), - SOC_SINGLE("ALC Capture Attack", WM8983_ALC_CONTROL_3, 0, 10, 0), - SOC_SINGLE("ALC Capture Hold", WM8983_ALC_CONTROL_2, 4, 10, 0), - SOC_SINGLE("ALC Capture Decay", WM8983_ALC_CONTROL_3, 4, 10, 0), - SOC_ENUM("ALC Mode", alc_mode), - SOC_SINGLE("ALC Capture NG Switch", WM8983_NOISE_GATE, - 3, 1, 0), - SOC_SINGLE("ALC Capture NG Threshold", WM8983_NOISE_GATE, - 0, 7, 1), - - SOC_DOUBLE_R_TLV("Capture Volume", WM8983_LEFT_ADC_DIGITAL_VOL, - WM8983_RIGHT_ADC_DIGITAL_VOL, 0, 255, 0, adc_tlv), - SOC_DOUBLE_R("Capture PGA ZC Switch", WM8983_LEFT_INP_PGA_GAIN_CTRL, - WM8983_RIGHT_INP_PGA_GAIN_CTRL, 7, 1, 0), - SOC_DOUBLE_R_TLV("Capture PGA Volume", WM8983_LEFT_INP_PGA_GAIN_CTRL, - WM8983_RIGHT_INP_PGA_GAIN_CTRL, 0, 63, 0, pga_vol_tlv), - - SOC_DOUBLE_R_TLV("Capture PGA Boost Volume", - WM8983_LEFT_ADC_BOOST_CTRL, WM8983_RIGHT_ADC_BOOST_CTRL, - 8, 1, 0, pga_boost_tlv), - - SOC_DOUBLE("ADC Inversion Switch", WM8983_ADC_CONTROL, 0, 1, 1, 0), - SOC_SINGLE("ADC 128x Oversampling Switch", WM8983_ADC_CONTROL, 8, 1, 0), - - SOC_DOUBLE_R_TLV("Playback Volume", WM8983_LEFT_DAC_DIGITAL_VOL, - WM8983_RIGHT_DAC_DIGITAL_VOL, 0, 255, 0, dac_tlv), - - SOC_SINGLE("DAC Playback Limiter Switch", WM8983_DAC_LIMITER_1, 8, 1, 0), - SOC_SINGLE("DAC Playback Limiter Decay", WM8983_DAC_LIMITER_1, 4, 10, 0), - SOC_SINGLE("DAC Playback Limiter Attack", WM8983_DAC_LIMITER_1, 0, 11, 0), - SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8983_DAC_LIMITER_2, - 4, 7, 1, lim_thresh_tlv), - SOC_SINGLE_TLV("DAC Playback Limiter Boost Volume", WM8983_DAC_LIMITER_2, - 0, 12, 0, lim_boost_tlv), - SOC_DOUBLE("DAC Inversion Switch", WM8983_DAC_CONTROL, 0, 1, 1, 0), - SOC_SINGLE("DAC Auto Mute Switch", WM8983_DAC_CONTROL, 2, 1, 0), - SOC_SINGLE("DAC 128x Oversampling Switch", WM8983_DAC_CONTROL, 3, 1, 0), - - SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8983_LOUT1_HP_VOLUME_CTRL, - WM8983_ROUT1_HP_VOLUME_CTRL, 0, 63, 0, out_tlv), - SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8983_LOUT1_HP_VOLUME_CTRL, - WM8983_ROUT1_HP_VOLUME_CTRL, 7, 1, 0), - SOC_DOUBLE_R("Headphone Switch", WM8983_LOUT1_HP_VOLUME_CTRL, - WM8983_ROUT1_HP_VOLUME_CTRL, 6, 1, 1), - - SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8983_LOUT2_SPK_VOLUME_CTRL, - WM8983_ROUT2_SPK_VOLUME_CTRL, 0, 63, 0, out_tlv), - SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8983_LOUT2_SPK_VOLUME_CTRL, - WM8983_ROUT2_SPK_VOLUME_CTRL, 7, 1, 0), - SOC_DOUBLE_R("Speaker Switch", WM8983_LOUT2_SPK_VOLUME_CTRL, - WM8983_ROUT2_SPK_VOLUME_CTRL, 6, 1, 1), - - SOC_SINGLE("OUT3 Switch", WM8983_OUT3_MIXER_CTRL, - 6, 1, 1), - - SOC_SINGLE("OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL, - 6, 1, 1), - - SOC_SINGLE("High Pass Filter Switch", WM8983_ADC_CONTROL, 8, 1, 0), - SOC_ENUM("High Pass Filter Mode", filter_mode), - SOC_SINGLE("High Pass Filter Cutoff", WM8983_ADC_CONTROL, 4, 7, 0), - - SOC_DOUBLE_R_TLV("Aux Bypass Volume", - WM8983_LEFT_MIXER_CTRL, WM8983_RIGHT_MIXER_CTRL, 6, 7, 0, - aux_tlv), - - SOC_DOUBLE_R_TLV("Input PGA Bypass Volume", - WM8983_LEFT_MIXER_CTRL, WM8983_RIGHT_MIXER_CTRL, 2, 7, 0, - bypass_tlv), - - SOC_ENUM_EXT("Equalizer Function", eqmode, eqmode_get, eqmode_put), - SOC_ENUM("EQ1 Cutoff", eq1_cutoff), - SOC_SINGLE_TLV("EQ1 Volume", WM8983_EQ1_LOW_SHELF, 0, 24, 1, eq_tlv), - SOC_ENUM("EQ2 Bandwith", eq2_bw), - SOC_ENUM("EQ2 Cutoff", eq2_cutoff), - SOC_SINGLE_TLV("EQ2 Volume", WM8983_EQ2_PEAK_1, 0, 24, 1, eq_tlv), - SOC_ENUM("EQ3 Bandwith", eq3_bw), - SOC_ENUM("EQ3 Cutoff", eq3_cutoff), - SOC_SINGLE_TLV("EQ3 Volume", WM8983_EQ3_PEAK_2, 0, 24, 1, eq_tlv), - SOC_ENUM("EQ4 Bandwith", eq4_bw), - SOC_ENUM("EQ4 Cutoff", eq4_cutoff), - SOC_SINGLE_TLV("EQ4 Volume", WM8983_EQ4_PEAK_3, 0, 24, 1, eq_tlv), - SOC_ENUM("EQ5 Cutoff", eq5_cutoff), - SOC_SINGLE_TLV("EQ5 Volume", WM8983_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv), - - SOC_ENUM("3D Depth", depth_3d), - - SOC_ENUM("Speaker Mode", speaker_mode) -}; - -static const struct snd_kcontrol_new left_out_mixer[] = { - SOC_DAPM_SINGLE("Line Switch", WM8983_LEFT_MIXER_CTRL, 1, 1, 0), - SOC_DAPM_SINGLE("Aux Switch", WM8983_LEFT_MIXER_CTRL, 5, 1, 0), - SOC_DAPM_SINGLE("PCM Switch", WM8983_LEFT_MIXER_CTRL, 0, 1, 0), -}; - -static const struct snd_kcontrol_new right_out_mixer[] = { - SOC_DAPM_SINGLE("Line Switch", WM8983_RIGHT_MIXER_CTRL, 1, 1, 0), - SOC_DAPM_SINGLE("Aux Switch", WM8983_RIGHT_MIXER_CTRL, 5, 1, 0), - SOC_DAPM_SINGLE("PCM Switch", WM8983_RIGHT_MIXER_CTRL, 0, 1, 0), -}; - -static const struct snd_kcontrol_new left_input_mixer[] = { - SOC_DAPM_SINGLE("L2 Switch", WM8983_INPUT_CTRL, 2, 1, 0), - SOC_DAPM_SINGLE("MicN Switch", WM8983_INPUT_CTRL, 1, 1, 0), - SOC_DAPM_SINGLE("MicP Switch", WM8983_INPUT_CTRL, 0, 1, 0), -}; - -static const struct snd_kcontrol_new right_input_mixer[] = { - SOC_DAPM_SINGLE("R2 Switch", WM8983_INPUT_CTRL, 6, 1, 0), - SOC_DAPM_SINGLE("MicN Switch", WM8983_INPUT_CTRL, 5, 1, 0), - SOC_DAPM_SINGLE("MicP Switch", WM8983_INPUT_CTRL, 4, 1, 0), -}; - -static const struct snd_kcontrol_new left_boost_mixer[] = { - SOC_DAPM_SINGLE_TLV("L2 Volume", WM8983_LEFT_ADC_BOOST_CTRL, - 4, 7, 0, boost_tlv), - SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8983_LEFT_ADC_BOOST_CTRL, - 0, 7, 0, boost_tlv) -}; - -static const struct snd_kcontrol_new out3_mixer[] = { - SOC_DAPM_SINGLE("LMIX2OUT3 Switch", WM8983_OUT3_MIXER_CTRL, - 1, 1, 0), - SOC_DAPM_SINGLE("LDAC2OUT3 Switch", WM8983_OUT3_MIXER_CTRL, - 0, 1, 0), -}; - -static const struct snd_kcontrol_new out4_mixer[] = { - SOC_DAPM_SINGLE("LMIX2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL, - 4, 1, 0), - SOC_DAPM_SINGLE("RMIX2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL, - 1, 1, 0), - SOC_DAPM_SINGLE("LDAC2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL, - 3, 1, 0), - SOC_DAPM_SINGLE("RDAC2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL, - 0, 1, 0), -}; - -static const struct snd_kcontrol_new right_boost_mixer[] = { - SOC_DAPM_SINGLE_TLV("R2 Volume", WM8983_RIGHT_ADC_BOOST_CTRL, - 4, 7, 0, boost_tlv), - SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8983_RIGHT_ADC_BOOST_CTRL, - 0, 7, 0, boost_tlv) -}; - -static const struct snd_soc_dapm_widget wm8983_dapm_widgets[] = { - SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8983_POWER_MANAGEMENT_3, - 0, 0), - SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8983_POWER_MANAGEMENT_3, - 1, 0), - SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8983_POWER_MANAGEMENT_2, - 0, 0), - SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8983_POWER_MANAGEMENT_2, - 1, 0), - - SND_SOC_DAPM_MIXER("Left Output Mixer", WM8983_POWER_MANAGEMENT_3, - 2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)), - SND_SOC_DAPM_MIXER("Right Output Mixer", WM8983_POWER_MANAGEMENT_3, - 3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)), - - SND_SOC_DAPM_MIXER("Left Input Mixer", WM8983_POWER_MANAGEMENT_2, - 2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)), - SND_SOC_DAPM_MIXER("Right Input Mixer", WM8983_POWER_MANAGEMENT_2, - 3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)), - - SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8983_POWER_MANAGEMENT_2, - 4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)), - SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8983_POWER_MANAGEMENT_2, - 5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)), - - SND_SOC_DAPM_MIXER("OUT3 Mixer", WM8983_POWER_MANAGEMENT_1, - 6, 0, out3_mixer, ARRAY_SIZE(out3_mixer)), - - SND_SOC_DAPM_MIXER("OUT4 Mixer", WM8983_POWER_MANAGEMENT_1, - 7, 0, out4_mixer, ARRAY_SIZE(out4_mixer)), - - SND_SOC_DAPM_PGA("Left Capture PGA", WM8983_LEFT_INP_PGA_GAIN_CTRL, - 6, 1, NULL, 0), - SND_SOC_DAPM_PGA("Right Capture PGA", WM8983_RIGHT_INP_PGA_GAIN_CTRL, - 6, 1, NULL, 0), - - SND_SOC_DAPM_PGA("Left Headphone Out", WM8983_POWER_MANAGEMENT_2, - 7, 0, NULL, 0), - SND_SOC_DAPM_PGA("Right Headphone Out", WM8983_POWER_MANAGEMENT_2, - 8, 0, NULL, 0), - - SND_SOC_DAPM_PGA("Left Speaker Out", WM8983_POWER_MANAGEMENT_3, - 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("Right Speaker Out", WM8983_POWER_MANAGEMENT_3, - 6, 0, NULL, 0), - - SND_SOC_DAPM_PGA("OUT3 Out", WM8983_POWER_MANAGEMENT_3, - 7, 0, NULL, 0), - - SND_SOC_DAPM_PGA("OUT4 Out", WM8983_POWER_MANAGEMENT_3, - 8, 0, NULL, 0), - - SND_SOC_DAPM_MICBIAS("Mic Bias", WM8983_POWER_MANAGEMENT_1, 4, 0), - - SND_SOC_DAPM_INPUT("LIN"), - SND_SOC_DAPM_INPUT("LIP"), - SND_SOC_DAPM_INPUT("RIN"), - SND_SOC_DAPM_INPUT("RIP"), - SND_SOC_DAPM_INPUT("AUXL"), - SND_SOC_DAPM_INPUT("AUXR"), - SND_SOC_DAPM_INPUT("L2"), - SND_SOC_DAPM_INPUT("R2"), - SND_SOC_DAPM_OUTPUT("HPL"), - SND_SOC_DAPM_OUTPUT("HPR"), - SND_SOC_DAPM_OUTPUT("SPKL"), - SND_SOC_DAPM_OUTPUT("SPKR"), - SND_SOC_DAPM_OUTPUT("OUT3"), - SND_SOC_DAPM_OUTPUT("OUT4") -}; - -static const struct snd_soc_dapm_route wm8983_audio_map[] = { - { "OUT3 Mixer", "LMIX2OUT3 Switch", "Left Output Mixer" }, - { "OUT3 Mixer", "LDAC2OUT3 Switch", "Left DAC" }, - - { "OUT3 Out", NULL, "OUT3 Mixer" }, - { "OUT3", NULL, "OUT3 Out" }, - - { "OUT4 Mixer", "LMIX2OUT4 Switch", "Left Output Mixer" }, - { "OUT4 Mixer", "RMIX2OUT4 Switch", "Right Output Mixer" }, - { "OUT4 Mixer", "LDAC2OUT4 Switch", "Left DAC" }, - { "OUT4 Mixer", "RDAC2OUT4 Switch", "Right DAC" }, - - { "OUT4 Out", NULL, "OUT4 Mixer" }, - { "OUT4", NULL, "OUT4 Out" }, - - { "Right Output Mixer", "PCM Switch", "Right DAC" }, - { "Right Output Mixer", "Aux Switch", "AUXR" }, - { "Right Output Mixer", "Line Switch", "Right Boost Mixer" }, - - { "Left Output Mixer", "PCM Switch", "Left DAC" }, - { "Left Output Mixer", "Aux Switch", "AUXL" }, - { "Left Output Mixer", "Line Switch", "Left Boost Mixer" }, - - { "Right Headphone Out", NULL, "Right Output Mixer" }, - { "HPR", NULL, "Right Headphone Out" }, - - { "Left Headphone Out", NULL, "Left Output Mixer" }, - { "HPL", NULL, "Left Headphone Out" }, - - { "Right Speaker Out", NULL, "Right Output Mixer" }, - { "SPKR", NULL, "Right Speaker Out" }, - - { "Left Speaker Out", NULL, "Left Output Mixer" }, - { "SPKL", NULL, "Left Speaker Out" }, - - { "Right ADC", NULL, "Right Boost Mixer" }, - - { "Right Boost Mixer", "AUXR Volume", "AUXR" }, - { "Right Boost Mixer", NULL, "Right Capture PGA" }, - { "Right Boost Mixer", "R2 Volume", "R2" }, - - { "Left ADC", NULL, "Left Boost Mixer" }, - - { "Left Boost Mixer", "AUXL Volume", "AUXL" }, - { "Left Boost Mixer", NULL, "Left Capture PGA" }, - { "Left Boost Mixer", "L2 Volume", "L2" }, - - { "Right Capture PGA", NULL, "Right Input Mixer" }, - { "Left Capture PGA", NULL, "Left Input Mixer" }, - - { "Right Input Mixer", "R2 Switch", "R2" }, - { "Right Input Mixer", "MicN Switch", "RIN" }, - { "Right Input Mixer", "MicP Switch", "RIP" }, - - { "Left Input Mixer", "L2 Switch", "L2" }, - { "Left Input Mixer", "MicN Switch", "LIN" }, - { "Left Input Mixer", "MicP Switch", "LIP" }, -}; - -static int eqmode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg; - - reg = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF); - if (reg & WM8983_EQ3DMODE) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; - - return 0; -} - -static int eqmode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int regpwr2, regpwr3; - unsigned int reg_eq; - - if (ucontrol->value.integer.value[0] != 0 - && ucontrol->value.integer.value[0] != 1) - return -EINVAL; - - reg_eq = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF); - switch ((reg_eq & WM8983_EQ3DMODE) >> WM8983_EQ3DMODE_SHIFT) { - case 0: - if (!ucontrol->value.integer.value[0]) - return 0; - break; - case 1: - if (ucontrol->value.integer.value[0]) - return 0; - break; - } - - regpwr2 = snd_soc_read(codec, WM8983_POWER_MANAGEMENT_2); - regpwr3 = snd_soc_read(codec, WM8983_POWER_MANAGEMENT_3); - /* disable the DACs and ADCs */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_2, - WM8983_ADCENR_MASK | WM8983_ADCENL_MASK, 0); - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_3, - WM8983_DACENR_MASK | WM8983_DACENL_MASK, 0); - /* set the desired eqmode */ - snd_soc_update_bits(codec, WM8983_EQ1_LOW_SHELF, - WM8983_EQ3DMODE_MASK, - ucontrol->value.integer.value[0] - << WM8983_EQ3DMODE_SHIFT); - /* restore DAC/ADC configuration */ - snd_soc_write(codec, WM8983_POWER_MANAGEMENT_2, regpwr2); - snd_soc_write(codec, WM8983_POWER_MANAGEMENT_3, regpwr3); - return 0; -} - -static int wm8983_readable(struct snd_soc_codec *codec, unsigned int reg) -{ - if (reg > WM8983_MAX_REGISTER) - return 0; - - return wm8983_access_masks[reg].read != 0; -} - -static int wm8983_dac_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - - return snd_soc_update_bits(codec, WM8983_DAC_CONTROL, - WM8983_SOFTMUTE_MASK, - !!mute << WM8983_SOFTMUTE_SHIFT); -} - -static int wm8983_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct snd_soc_codec *codec = dai->codec; - u16 format, master, bcp, lrp; - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - format = 0x2; - break; - case SND_SOC_DAIFMT_RIGHT_J: - format = 0x0; - break; - case SND_SOC_DAIFMT_LEFT_J: - format = 0x1; - break; - case SND_SOC_DAIFMT_DSP_A: - case SND_SOC_DAIFMT_DSP_B: - format = 0x3; - break; - default: - dev_err(dai->dev, "Unknown dai format\n"); - return -EINVAL; - } - - snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE, - WM8983_FMT_MASK, format << WM8983_FMT_SHIFT); - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - master = 1; - break; - case SND_SOC_DAIFMT_CBS_CFS: - master = 0; - break; - default: - dev_err(dai->dev, "Unknown master/slave configuration\n"); - return -EINVAL; - } - - snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL, - WM8983_MS_MASK, master << WM8983_MS_SHIFT); - - /* FIXME: We don't currently support DSP A/B modes */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_DSP_A: - case SND_SOC_DAIFMT_DSP_B: - dev_err(dai->dev, "DSP A/B modes are not supported\n"); - return -EINVAL; - default: - break; - } - - bcp = lrp = 0; - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_IB_IF: - bcp = lrp = 1; - break; - case SND_SOC_DAIFMT_IB_NF: - bcp = 1; - break; - case SND_SOC_DAIFMT_NB_IF: - lrp = 1; - break; - default: - dev_err(dai->dev, "Unknown polarity configuration\n"); - return -EINVAL; - } - - snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE, - WM8983_LRCP_MASK, lrp << WM8983_LRCP_SHIFT); - snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE, - WM8983_BCP_MASK, bcp << WM8983_BCP_SHIFT); - return 0; -} - -static int wm8983_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - int i; - struct snd_soc_codec *codec = dai->codec; - struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec); - u16 blen, srate_idx; - u32 tmp; - int srate_best; - int ret; - - ret = snd_soc_params_to_bclk(params); - if (ret < 0) { - dev_err(codec->dev, "Failed to convert params to bclk: %d\n", ret); - return ret; - } - - wm8983->bclk = ret; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - blen = 0x0; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - blen = 0x1; - break; - case SNDRV_PCM_FORMAT_S24_LE: - blen = 0x2; - break; - case SNDRV_PCM_FORMAT_S32_LE: - blen = 0x3; - break; - default: - dev_err(dai->dev, "Unsupported word length %u\n", - params_format(params)); - return -EINVAL; - } - - snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE, - WM8983_WL_MASK, blen << WM8983_WL_SHIFT); - - /* - * match to the nearest possible sample rate and rely - * on the array index to configure the SR register - */ - srate_idx = 0; - srate_best = abs(srates[0] - params_rate(params)); - for (i = 1; i < ARRAY_SIZE(srates); ++i) { - if (abs(srates[i] - params_rate(params)) >= srate_best) - continue; - srate_idx = i; - srate_best = abs(srates[i] - params_rate(params)); - } - - dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]); - snd_soc_update_bits(codec, WM8983_ADDITIONAL_CONTROL, - WM8983_SR_MASK, srate_idx << WM8983_SR_SHIFT); - - dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8983->bclk); - dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8983->sysclk); - - for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) { - if (wm8983->sysclk / params_rate(params) - == fs_ratios[i].ratio) - break; - } - - if (i == ARRAY_SIZE(fs_ratios)) { - dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n", - wm8983->sysclk, params_rate(params)); - return -EINVAL; - } - - dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio); - snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL, - WM8983_MCLKDIV_MASK, i << WM8983_MCLKDIV_SHIFT); - - /* select the appropriate bclk divider */ - tmp = (wm8983->sysclk / fs_ratios[i].div) * 10; - for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) { - if (wm8983->bclk == tmp / bclk_divs[i]) - break; - } - - if (i == ARRAY_SIZE(bclk_divs)) { - dev_err(dai->dev, "No matching BCLK divider found\n"); - return -EINVAL; - } - - dev_dbg(dai->dev, "BCLK div = %d\n", i); - snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL, - WM8983_BCLKDIV_MASK, i << WM8983_BCLKDIV_SHIFT); - - return 0; -} - -struct pll_div { - u32 div2:1; - u32 n:4; - u32 k:24; -}; - -#define FIXED_PLL_SIZE ((1ULL << 24) * 10) -static int pll_factors(struct pll_div *pll_div, unsigned int target, - unsigned int source) -{ - u64 Kpart; - unsigned long int K, Ndiv, Nmod; - - pll_div->div2 = 0; - Ndiv = target / source; - if (Ndiv < 6) { - source >>= 1; - pll_div->div2 = 1; - Ndiv = target / source; - } - - if (Ndiv < 6 || Ndiv > 12) { - printk(KERN_ERR "%s: WM8983 N value is not within" - " the recommended range: %lu\n", __func__, Ndiv); - return -EINVAL; - } - pll_div->n = Ndiv; - - Nmod = target % source; - Kpart = FIXED_PLL_SIZE * (u64)Nmod; - - do_div(Kpart, source); - - K = Kpart & 0xffffffff; - if ((K % 10) >= 5) - K += 5; - K /= 10; - pll_div->k = K; - return 0; -} - -static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id, - int source, unsigned int freq_in, - unsigned int freq_out) -{ - int ret; - struct snd_soc_codec *codec; - struct pll_div pll_div; - - codec = dai->codec; - if (freq_in && freq_out) { - ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in); - if (ret) - return ret; - } - - /* disable the PLL before re-programming it */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_PLLEN_MASK, 0); - - if (!freq_in || !freq_out) - return 0; - - /* set PLLN and PRESCALE */ - snd_soc_write(codec, WM8983_PLL_N, - (pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT) - | pll_div.n); - /* set PLLK */ - snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff); - snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff); - snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18)); - /* enable the PLL */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_PLLEN_MASK, WM8983_PLLEN); - return 0; -} - -static int wm8983_set_sysclk(struct snd_soc_dai *dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = dai->codec; - struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec); - - switch (clk_id) { - case WM8983_CLKSRC_MCLK: - snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL, - WM8983_CLKSEL_MASK, 0); - break; - case WM8983_CLKSRC_PLL: - snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL, - WM8983_CLKSEL_MASK, WM8983_CLKSEL); - break; - default: - dev_err(dai->dev, "Unknown clock source: %d\n", clk_id); - return -EINVAL; - } - - wm8983->sysclk = freq; - return 0; -} - -static int wm8983_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - int ret; - - switch (level) { - case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: - /* VMID at 100k */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_VMIDSEL_MASK, - 1 << WM8983_VMIDSEL_SHIFT); - 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; - } - /* enable anti-pop features */ - snd_soc_update_bits(codec, WM8983_OUT4_TO_ADC, - WM8983_POBCTRL_MASK | WM8983_DELEN_MASK, - WM8983_POBCTRL | WM8983_DELEN); - /* enable thermal shutdown */ - snd_soc_update_bits(codec, WM8983_OUTPUT_CTRL, - WM8983_TSDEN_MASK, WM8983_TSDEN); - /* enable BIASEN */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_BIASEN_MASK, WM8983_BIASEN); - /* VMID at 100k */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_VMIDSEL_MASK, - 1 << WM8983_VMIDSEL_SHIFT); - msleep(250); - /* disable anti-pop features */ - snd_soc_update_bits(codec, WM8983_OUT4_TO_ADC, - WM8983_POBCTRL_MASK | - WM8983_DELEN_MASK, 0); - } - - /* VMID at 500k */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_VMIDSEL_MASK, - 2 << WM8983_VMIDSEL_SHIFT); - break; - case SND_SOC_BIAS_OFF: - /* disable thermal shutdown */ - snd_soc_update_bits(codec, WM8983_OUTPUT_CTRL, - WM8983_TSDEN_MASK, 0); - /* disable VMIDSEL and BIASEN */ - snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1, - WM8983_VMIDSEL_MASK | WM8983_BIASEN_MASK, - 0); - /* wait for VMID to discharge */ - msleep(100); - snd_soc_write(codec, WM8983_POWER_MANAGEMENT_1, 0); - snd_soc_write(codec, WM8983_POWER_MANAGEMENT_2, 0); - snd_soc_write(codec, WM8983_POWER_MANAGEMENT_3, 0); - break; - } - - codec->dapm.bias_level = level; - return 0; -} - -#ifdef CONFIG_PM -static int wm8983_suspend(struct snd_soc_codec *codec, pm_message_t state) -{ - wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8983_resume(struct snd_soc_codec *codec) -{ - wm8983_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8983_suspend NULL -#define wm8983_resume NULL -#endif - -static int wm8983_remove(struct snd_soc_codec *codec) -{ - wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8983_probe(struct snd_soc_codec *codec) -{ - int ret; - struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec); - int i; - - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8983->control_type); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); - return ret; - } - - ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0x8983); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset: %d\n", ret); - return ret; - } - - /* set the vol/gain update bits */ - for (i = 0; i < ARRAY_SIZE(vol_update_regs); ++i) - snd_soc_update_bits(codec, vol_update_regs[i], - 0x100, 0x100); - - /* mute all outputs and set PGAs to minimum gain */ - for (i = WM8983_LOUT1_HP_VOLUME_CTRL; - i <= WM8983_OUT4_MONO_MIX_CTRL; ++i) - snd_soc_update_bits(codec, i, 0x40, 0x40); - - /* enable soft mute */ - snd_soc_update_bits(codec, WM8983_DAC_CONTROL, - WM8983_SOFTMUTE_MASK, - WM8983_SOFTMUTE); - - /* enable BIASCUT */ - snd_soc_update_bits(codec, WM8983_BIAS_CTRL, - WM8983_BIASCUT, WM8983_BIASCUT); - return 0; -} - -static struct snd_soc_dai_ops wm8983_dai_ops = { - .digital_mute = wm8983_dac_mute, - .hw_params = wm8983_hw_params, - .set_fmt = wm8983_set_fmt, - .set_sysclk = wm8983_set_sysclk, - .set_pll = wm8983_set_pll -}; - -#define WM8983_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -static struct snd_soc_dai_driver wm8983_dai = { - .name = "wm8983-hifi", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = WM8983_FORMATS, - }, - .capture = { - .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = WM8983_FORMATS, - }, - .ops = &wm8983_dai_ops, - .symmetric_rates = 1 -}; - -static struct snd_soc_codec_driver soc_codec_dev_wm8983 = { - .probe = wm8983_probe, - .remove = wm8983_remove, - .suspend = wm8983_suspend, - .resume = wm8983_resume, - .set_bias_level = wm8983_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8983_reg_defs), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8983_reg_defs, - .controls = wm8983_snd_controls, - .num_controls = ARRAY_SIZE(wm8983_snd_controls), - .dapm_widgets = wm8983_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8983_dapm_widgets), - .dapm_routes = wm8983_audio_map, - .num_dapm_routes = ARRAY_SIZE(wm8983_audio_map), - .readable_register = wm8983_readable -}; - -#if defined(CONFIG_SPI_MASTER) -static int __devinit wm8983_spi_probe(struct spi_device *spi) -{ - struct wm8983_priv *wm8983; - int ret; - - wm8983 = kzalloc(sizeof *wm8983, GFP_KERNEL); - if (!wm8983) - return -ENOMEM; - - wm8983->control_type = SND_SOC_SPI; - spi_set_drvdata(spi, wm8983); - - ret = snd_soc_register_codec(&spi->dev, - &soc_codec_dev_wm8983, &wm8983_dai, 1); - if (ret < 0) - kfree(wm8983); - return ret; -} - -static int __devexit wm8983_spi_remove(struct spi_device *spi) -{ - snd_soc_unregister_codec(&spi->dev); - kfree(spi_get_drvdata(spi)); - return 0; -} - -static struct spi_driver wm8983_spi_driver = { - .driver = { - .name = "wm8983", - .owner = THIS_MODULE, - }, - .probe = wm8983_spi_probe, - .remove = __devexit_p(wm8983_spi_remove) -}; -#endif - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8983_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm8983_priv *wm8983; - int ret; - - wm8983 = kzalloc(sizeof *wm8983, GFP_KERNEL); - if (!wm8983) - return -ENOMEM; - - wm8983->control_type = SND_SOC_I2C; - i2c_set_clientdata(i2c, wm8983); - - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_wm8983, &wm8983_dai, 1); - if (ret < 0) - kfree(wm8983); - return ret; -} - -static __devexit int wm8983_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 wm8983_i2c_id[] = { - { "wm8983", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8983_i2c_id); - -static struct i2c_driver wm8983_i2c_driver = { - .driver = { - .name = "wm8983", - .owner = THIS_MODULE, - }, - .probe = wm8983_i2c_probe, - .remove = __devexit_p(wm8983_i2c_remove), - .id_table = wm8983_i2c_id -}; -#endif - -static int __init wm8983_modinit(void) -{ - int ret = 0; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&wm8983_i2c_driver); - if (ret) { - printk(KERN_ERR "Failed to register wm8983 I2C driver: %d\n", - ret); - } -#endif -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&wm8983_spi_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8983 SPI driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(wm8983_modinit); - -static void __exit wm8983_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm8983_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8983_spi_driver); -#endif -} -module_exit(wm8983_exit); - -MODULE_DESCRIPTION("ASoC WM8983 driver"); -MODULE_AUTHOR("Dimitris Papastamos "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/wm8983.h b/trunk/sound/soc/codecs/wm8983.h deleted file mode 100644 index 71ee619c2742..000000000000 --- a/trunk/sound/soc/codecs/wm8983.h +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * wm8983.h -- WM8983 ALSA SoC Audio driver - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Dimitris Papastamos - * - * 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 _WM8983_H -#define _WM8983_H - -/* - * Register values. - */ -#define WM8983_SOFTWARE_RESET 0x00 -#define WM8983_POWER_MANAGEMENT_1 0x01 -#define WM8983_POWER_MANAGEMENT_2 0x02 -#define WM8983_POWER_MANAGEMENT_3 0x03 -#define WM8983_AUDIO_INTERFACE 0x04 -#define WM8983_COMPANDING_CONTROL 0x05 -#define WM8983_CLOCK_GEN_CONTROL 0x06 -#define WM8983_ADDITIONAL_CONTROL 0x07 -#define WM8983_GPIO_CONTROL 0x08 -#define WM8983_JACK_DETECT_CONTROL_1 0x09 -#define WM8983_DAC_CONTROL 0x0A -#define WM8983_LEFT_DAC_DIGITAL_VOL 0x0B -#define WM8983_RIGHT_DAC_DIGITAL_VOL 0x0C -#define WM8983_JACK_DETECT_CONTROL_2 0x0D -#define WM8983_ADC_CONTROL 0x0E -#define WM8983_LEFT_ADC_DIGITAL_VOL 0x0F -#define WM8983_RIGHT_ADC_DIGITAL_VOL 0x10 -#define WM8983_EQ1_LOW_SHELF 0x12 -#define WM8983_EQ2_PEAK_1 0x13 -#define WM8983_EQ3_PEAK_2 0x14 -#define WM8983_EQ4_PEAK_3 0x15 -#define WM8983_EQ5_HIGH_SHELF 0x16 -#define WM8983_DAC_LIMITER_1 0x18 -#define WM8983_DAC_LIMITER_2 0x19 -#define WM8983_NOTCH_FILTER_1 0x1B -#define WM8983_NOTCH_FILTER_2 0x1C -#define WM8983_NOTCH_FILTER_3 0x1D -#define WM8983_NOTCH_FILTER_4 0x1E -#define WM8983_ALC_CONTROL_1 0x20 -#define WM8983_ALC_CONTROL_2 0x21 -#define WM8983_ALC_CONTROL_3 0x22 -#define WM8983_NOISE_GATE 0x23 -#define WM8983_PLL_N 0x24 -#define WM8983_PLL_K_1 0x25 -#define WM8983_PLL_K_2 0x26 -#define WM8983_PLL_K_3 0x27 -#define WM8983_3D_CONTROL 0x29 -#define WM8983_OUT4_TO_ADC 0x2A -#define WM8983_BEEP_CONTROL 0x2B -#define WM8983_INPUT_CTRL 0x2C -#define WM8983_LEFT_INP_PGA_GAIN_CTRL 0x2D -#define WM8983_RIGHT_INP_PGA_GAIN_CTRL 0x2E -#define WM8983_LEFT_ADC_BOOST_CTRL 0x2F -#define WM8983_RIGHT_ADC_BOOST_CTRL 0x30 -#define WM8983_OUTPUT_CTRL 0x31 -#define WM8983_LEFT_MIXER_CTRL 0x32 -#define WM8983_RIGHT_MIXER_CTRL 0x33 -#define WM8983_LOUT1_HP_VOLUME_CTRL 0x34 -#define WM8983_ROUT1_HP_VOLUME_CTRL 0x35 -#define WM8983_LOUT2_SPK_VOLUME_CTRL 0x36 -#define WM8983_ROUT2_SPK_VOLUME_CTRL 0x37 -#define WM8983_OUT3_MIXER_CTRL 0x38 -#define WM8983_OUT4_MONO_MIX_CTRL 0x39 -#define WM8983_BIAS_CTRL 0x3D - -#define WM8983_REGISTER_COUNT 59 -#define WM8983_MAX_REGISTER 0x3F - -/* - * Field Definitions. - */ - -/* - * R0 (0x00) - Software Reset - */ -#define WM8983_SOFTWARE_RESET_MASK 0x01FF /* SOFTWARE_RESET - [8:0] */ -#define WM8983_SOFTWARE_RESET_SHIFT 0 /* SOFTWARE_RESET - [8:0] */ -#define WM8983_SOFTWARE_RESET_WIDTH 9 /* SOFTWARE_RESET - [8:0] */ - -/* - * R1 (0x01) - Power management 1 - */ -#define WM8983_BUFDCOPEN 0x0100 /* BUFDCOPEN */ -#define WM8983_BUFDCOPEN_MASK 0x0100 /* BUFDCOPEN */ -#define WM8983_BUFDCOPEN_SHIFT 8 /* BUFDCOPEN */ -#define WM8983_BUFDCOPEN_WIDTH 1 /* BUFDCOPEN */ -#define WM8983_OUT4MIXEN 0x0080 /* OUT4MIXEN */ -#define WM8983_OUT4MIXEN_MASK 0x0080 /* OUT4MIXEN */ -#define WM8983_OUT4MIXEN_SHIFT 7 /* OUT4MIXEN */ -#define WM8983_OUT4MIXEN_WIDTH 1 /* OUT4MIXEN */ -#define WM8983_OUT3MIXEN 0x0040 /* OUT3MIXEN */ -#define WM8983_OUT3MIXEN_MASK 0x0040 /* OUT3MIXEN */ -#define WM8983_OUT3MIXEN_SHIFT 6 /* OUT3MIXEN */ -#define WM8983_OUT3MIXEN_WIDTH 1 /* OUT3MIXEN */ -#define WM8983_PLLEN 0x0020 /* PLLEN */ -#define WM8983_PLLEN_MASK 0x0020 /* PLLEN */ -#define WM8983_PLLEN_SHIFT 5 /* PLLEN */ -#define WM8983_PLLEN_WIDTH 1 /* PLLEN */ -#define WM8983_MICBEN 0x0010 /* MICBEN */ -#define WM8983_MICBEN_MASK 0x0010 /* MICBEN */ -#define WM8983_MICBEN_SHIFT 4 /* MICBEN */ -#define WM8983_MICBEN_WIDTH 1 /* MICBEN */ -#define WM8983_BIASEN 0x0008 /* BIASEN */ -#define WM8983_BIASEN_MASK 0x0008 /* BIASEN */ -#define WM8983_BIASEN_SHIFT 3 /* BIASEN */ -#define WM8983_BIASEN_WIDTH 1 /* BIASEN */ -#define WM8983_BUFIOEN 0x0004 /* BUFIOEN */ -#define WM8983_BUFIOEN_MASK 0x0004 /* BUFIOEN */ -#define WM8983_BUFIOEN_SHIFT 2 /* BUFIOEN */ -#define WM8983_BUFIOEN_WIDTH 1 /* BUFIOEN */ -#define WM8983_VMIDSEL_MASK 0x0003 /* VMIDSEL - [1:0] */ -#define WM8983_VMIDSEL_SHIFT 0 /* VMIDSEL - [1:0] */ -#define WM8983_VMIDSEL_WIDTH 2 /* VMIDSEL - [1:0] */ - -/* - * R2 (0x02) - Power management 2 - */ -#define WM8983_ROUT1EN 0x0100 /* ROUT1EN */ -#define WM8983_ROUT1EN_MASK 0x0100 /* ROUT1EN */ -#define WM8983_ROUT1EN_SHIFT 8 /* ROUT1EN */ -#define WM8983_ROUT1EN_WIDTH 1 /* ROUT1EN */ -#define WM8983_LOUT1EN 0x0080 /* LOUT1EN */ -#define WM8983_LOUT1EN_MASK 0x0080 /* LOUT1EN */ -#define WM8983_LOUT1EN_SHIFT 7 /* LOUT1EN */ -#define WM8983_LOUT1EN_WIDTH 1 /* LOUT1EN */ -#define WM8983_SLEEP 0x0040 /* SLEEP */ -#define WM8983_SLEEP_MASK 0x0040 /* SLEEP */ -#define WM8983_SLEEP_SHIFT 6 /* SLEEP */ -#define WM8983_SLEEP_WIDTH 1 /* SLEEP */ -#define WM8983_BOOSTENR 0x0020 /* BOOSTENR */ -#define WM8983_BOOSTENR_MASK 0x0020 /* BOOSTENR */ -#define WM8983_BOOSTENR_SHIFT 5 /* BOOSTENR */ -#define WM8983_BOOSTENR_WIDTH 1 /* BOOSTENR */ -#define WM8983_BOOSTENL 0x0010 /* BOOSTENL */ -#define WM8983_BOOSTENL_MASK 0x0010 /* BOOSTENL */ -#define WM8983_BOOSTENL_SHIFT 4 /* BOOSTENL */ -#define WM8983_BOOSTENL_WIDTH 1 /* BOOSTENL */ -#define WM8983_INPGAENR 0x0008 /* INPGAENR */ -#define WM8983_INPGAENR_MASK 0x0008 /* INPGAENR */ -#define WM8983_INPGAENR_SHIFT 3 /* INPGAENR */ -#define WM8983_INPGAENR_WIDTH 1 /* INPGAENR */ -#define WM8983_INPPGAENL 0x0004 /* INPPGAENL */ -#define WM8983_INPPGAENL_MASK 0x0004 /* INPPGAENL */ -#define WM8983_INPPGAENL_SHIFT 2 /* INPPGAENL */ -#define WM8983_INPPGAENL_WIDTH 1 /* INPPGAENL */ -#define WM8983_ADCENR 0x0002 /* ADCENR */ -#define WM8983_ADCENR_MASK 0x0002 /* ADCENR */ -#define WM8983_ADCENR_SHIFT 1 /* ADCENR */ -#define WM8983_ADCENR_WIDTH 1 /* ADCENR */ -#define WM8983_ADCENL 0x0001 /* ADCENL */ -#define WM8983_ADCENL_MASK 0x0001 /* ADCENL */ -#define WM8983_ADCENL_SHIFT 0 /* ADCENL */ -#define WM8983_ADCENL_WIDTH 1 /* ADCENL */ - -/* - * R3 (0x03) - Power management 3 - */ -#define WM8983_OUT4EN 0x0100 /* OUT4EN */ -#define WM8983_OUT4EN_MASK 0x0100 /* OUT4EN */ -#define WM8983_OUT4EN_SHIFT 8 /* OUT4EN */ -#define WM8983_OUT4EN_WIDTH 1 /* OUT4EN */ -#define WM8983_OUT3EN 0x0080 /* OUT3EN */ -#define WM8983_OUT3EN_MASK 0x0080 /* OUT3EN */ -#define WM8983_OUT3EN_SHIFT 7 /* OUT3EN */ -#define WM8983_OUT3EN_WIDTH 1 /* OUT3EN */ -#define WM8983_LOUT2EN 0x0040 /* LOUT2EN */ -#define WM8983_LOUT2EN_MASK 0x0040 /* LOUT2EN */ -#define WM8983_LOUT2EN_SHIFT 6 /* LOUT2EN */ -#define WM8983_LOUT2EN_WIDTH 1 /* LOUT2EN */ -#define WM8983_ROUT2EN 0x0020 /* ROUT2EN */ -#define WM8983_ROUT2EN_MASK 0x0020 /* ROUT2EN */ -#define WM8983_ROUT2EN_SHIFT 5 /* ROUT2EN */ -#define WM8983_ROUT2EN_WIDTH 1 /* ROUT2EN */ -#define WM8983_RMIXEN 0x0008 /* RMIXEN */ -#define WM8983_RMIXEN_MASK 0x0008 /* RMIXEN */ -#define WM8983_RMIXEN_SHIFT 3 /* RMIXEN */ -#define WM8983_RMIXEN_WIDTH 1 /* RMIXEN */ -#define WM8983_LMIXEN 0x0004 /* LMIXEN */ -#define WM8983_LMIXEN_MASK 0x0004 /* LMIXEN */ -#define WM8983_LMIXEN_SHIFT 2 /* LMIXEN */ -#define WM8983_LMIXEN_WIDTH 1 /* LMIXEN */ -#define WM8983_DACENR 0x0002 /* DACENR */ -#define WM8983_DACENR_MASK 0x0002 /* DACENR */ -#define WM8983_DACENR_SHIFT 1 /* DACENR */ -#define WM8983_DACENR_WIDTH 1 /* DACENR */ -#define WM8983_DACENL 0x0001 /* DACENL */ -#define WM8983_DACENL_MASK 0x0001 /* DACENL */ -#define WM8983_DACENL_SHIFT 0 /* DACENL */ -#define WM8983_DACENL_WIDTH 1 /* DACENL */ - -/* - * R4 (0x04) - Audio Interface - */ -#define WM8983_BCP 0x0100 /* BCP */ -#define WM8983_BCP_MASK 0x0100 /* BCP */ -#define WM8983_BCP_SHIFT 8 /* BCP */ -#define WM8983_BCP_WIDTH 1 /* BCP */ -#define WM8983_LRCP 0x0080 /* LRCP */ -#define WM8983_LRCP_MASK 0x0080 /* LRCP */ -#define WM8983_LRCP_SHIFT 7 /* LRCP */ -#define WM8983_LRCP_WIDTH 1 /* LRCP */ -#define WM8983_WL_MASK 0x0060 /* WL - [6:5] */ -#define WM8983_WL_SHIFT 5 /* WL - [6:5] */ -#define WM8983_WL_WIDTH 2 /* WL - [6:5] */ -#define WM8983_FMT_MASK 0x0018 /* FMT - [4:3] */ -#define WM8983_FMT_SHIFT 3 /* FMT - [4:3] */ -#define WM8983_FMT_WIDTH 2 /* FMT - [4:3] */ -#define WM8983_DLRSWAP 0x0004 /* DLRSWAP */ -#define WM8983_DLRSWAP_MASK 0x0004 /* DLRSWAP */ -#define WM8983_DLRSWAP_SHIFT 2 /* DLRSWAP */ -#define WM8983_DLRSWAP_WIDTH 1 /* DLRSWAP */ -#define WM8983_ALRSWAP 0x0002 /* ALRSWAP */ -#define WM8983_ALRSWAP_MASK 0x0002 /* ALRSWAP */ -#define WM8983_ALRSWAP_SHIFT 1 /* ALRSWAP */ -#define WM8983_ALRSWAP_WIDTH 1 /* ALRSWAP */ -#define WM8983_MONO 0x0001 /* MONO */ -#define WM8983_MONO_MASK 0x0001 /* MONO */ -#define WM8983_MONO_SHIFT 0 /* MONO */ -#define WM8983_MONO_WIDTH 1 /* MONO */ - -/* - * R5 (0x05) - Companding control - */ -#define WM8983_WL8 0x0020 /* WL8 */ -#define WM8983_WL8_MASK 0x0020 /* WL8 */ -#define WM8983_WL8_SHIFT 5 /* WL8 */ -#define WM8983_WL8_WIDTH 1 /* WL8 */ -#define WM8983_DAC_COMP_MASK 0x0018 /* DAC_COMP - [4:3] */ -#define WM8983_DAC_COMP_SHIFT 3 /* DAC_COMP - [4:3] */ -#define WM8983_DAC_COMP_WIDTH 2 /* DAC_COMP - [4:3] */ -#define WM8983_ADC_COMP_MASK 0x0006 /* ADC_COMP - [2:1] */ -#define WM8983_ADC_COMP_SHIFT 1 /* ADC_COMP - [2:1] */ -#define WM8983_ADC_COMP_WIDTH 2 /* ADC_COMP - [2:1] */ -#define WM8983_LOOPBACK 0x0001 /* LOOPBACK */ -#define WM8983_LOOPBACK_MASK 0x0001 /* LOOPBACK */ -#define WM8983_LOOPBACK_SHIFT 0 /* LOOPBACK */ -#define WM8983_LOOPBACK_WIDTH 1 /* LOOPBACK */ - -/* - * R6 (0x06) - Clock Gen control - */ -#define WM8983_CLKSEL 0x0100 /* CLKSEL */ -#define WM8983_CLKSEL_MASK 0x0100 /* CLKSEL */ -#define WM8983_CLKSEL_SHIFT 8 /* CLKSEL */ -#define WM8983_CLKSEL_WIDTH 1 /* CLKSEL */ -#define WM8983_MCLKDIV_MASK 0x00E0 /* MCLKDIV - [7:5] */ -#define WM8983_MCLKDIV_SHIFT 5 /* MCLKDIV - [7:5] */ -#define WM8983_MCLKDIV_WIDTH 3 /* MCLKDIV - [7:5] */ -#define WM8983_BCLKDIV_MASK 0x001C /* BCLKDIV - [4:2] */ -#define WM8983_BCLKDIV_SHIFT 2 /* BCLKDIV - [4:2] */ -#define WM8983_BCLKDIV_WIDTH 3 /* BCLKDIV - [4:2] */ -#define WM8983_MS 0x0001 /* MS */ -#define WM8983_MS_MASK 0x0001 /* MS */ -#define WM8983_MS_SHIFT 0 /* MS */ -#define WM8983_MS_WIDTH 1 /* MS */ - -/* - * R7 (0x07) - Additional control - */ -#define WM8983_SR_MASK 0x000E /* SR - [3:1] */ -#define WM8983_SR_SHIFT 1 /* SR - [3:1] */ -#define WM8983_SR_WIDTH 3 /* SR - [3:1] */ -#define WM8983_SLOWCLKEN 0x0001 /* SLOWCLKEN */ -#define WM8983_SLOWCLKEN_MASK 0x0001 /* SLOWCLKEN */ -#define WM8983_SLOWCLKEN_SHIFT 0 /* SLOWCLKEN */ -#define WM8983_SLOWCLKEN_WIDTH 1 /* SLOWCLKEN */ - -/* - * R8 (0x08) - GPIO Control - */ -#define WM8983_OPCLKDIV_MASK 0x0030 /* OPCLKDIV - [5:4] */ -#define WM8983_OPCLKDIV_SHIFT 4 /* OPCLKDIV - [5:4] */ -#define WM8983_OPCLKDIV_WIDTH 2 /* OPCLKDIV - [5:4] */ -#define WM8983_GPIO1POL 0x0008 /* GPIO1POL */ -#define WM8983_GPIO1POL_MASK 0x0008 /* GPIO1POL */ -#define WM8983_GPIO1POL_SHIFT 3 /* GPIO1POL */ -#define WM8983_GPIO1POL_WIDTH 1 /* GPIO1POL */ -#define WM8983_GPIO1SEL_MASK 0x0007 /* GPIO1SEL - [2:0] */ -#define WM8983_GPIO1SEL_SHIFT 0 /* GPIO1SEL - [2:0] */ -#define WM8983_GPIO1SEL_WIDTH 3 /* GPIO1SEL - [2:0] */ - -/* - * R9 (0x09) - Jack Detect Control 1 - */ -#define WM8983_JD_VMID1 0x0100 /* JD_VMID1 */ -#define WM8983_JD_VMID1_MASK 0x0100 /* JD_VMID1 */ -#define WM8983_JD_VMID1_SHIFT 8 /* JD_VMID1 */ -#define WM8983_JD_VMID1_WIDTH 1 /* JD_VMID1 */ -#define WM8983_JD_VMID0 0x0080 /* JD_VMID0 */ -#define WM8983_JD_VMID0_MASK 0x0080 /* JD_VMID0 */ -#define WM8983_JD_VMID0_SHIFT 7 /* JD_VMID0 */ -#define WM8983_JD_VMID0_WIDTH 1 /* JD_VMID0 */ -#define WM8983_JD_EN 0x0040 /* JD_EN */ -#define WM8983_JD_EN_MASK 0x0040 /* JD_EN */ -#define WM8983_JD_EN_SHIFT 6 /* JD_EN */ -#define WM8983_JD_EN_WIDTH 1 /* JD_EN */ -#define WM8983_JD_SEL_MASK 0x0030 /* JD_SEL - [5:4] */ -#define WM8983_JD_SEL_SHIFT 4 /* JD_SEL - [5:4] */ -#define WM8983_JD_SEL_WIDTH 2 /* JD_SEL - [5:4] */ - -/* - * R10 (0x0A) - DAC Control - */ -#define WM8983_SOFTMUTE 0x0040 /* SOFTMUTE */ -#define WM8983_SOFTMUTE_MASK 0x0040 /* SOFTMUTE */ -#define WM8983_SOFTMUTE_SHIFT 6 /* SOFTMUTE */ -#define WM8983_SOFTMUTE_WIDTH 1 /* SOFTMUTE */ -#define WM8983_DACOSR128 0x0008 /* DACOSR128 */ -#define WM8983_DACOSR128_MASK 0x0008 /* DACOSR128 */ -#define WM8983_DACOSR128_SHIFT 3 /* DACOSR128 */ -#define WM8983_DACOSR128_WIDTH 1 /* DACOSR128 */ -#define WM8983_AMUTE 0x0004 /* AMUTE */ -#define WM8983_AMUTE_MASK 0x0004 /* AMUTE */ -#define WM8983_AMUTE_SHIFT 2 /* AMUTE */ -#define WM8983_AMUTE_WIDTH 1 /* AMUTE */ -#define WM8983_DACRPOL 0x0002 /* DACRPOL */ -#define WM8983_DACRPOL_MASK 0x0002 /* DACRPOL */ -#define WM8983_DACRPOL_SHIFT 1 /* DACRPOL */ -#define WM8983_DACRPOL_WIDTH 1 /* DACRPOL */ -#define WM8983_DACLPOL 0x0001 /* DACLPOL */ -#define WM8983_DACLPOL_MASK 0x0001 /* DACLPOL */ -#define WM8983_DACLPOL_SHIFT 0 /* DACLPOL */ -#define WM8983_DACLPOL_WIDTH 1 /* DACLPOL */ - -/* - * R11 (0x0B) - Left DAC digital Vol - */ -#define WM8983_DACVU 0x0100 /* DACVU */ -#define WM8983_DACVU_MASK 0x0100 /* DACVU */ -#define WM8983_DACVU_SHIFT 8 /* DACVU */ -#define WM8983_DACVU_WIDTH 1 /* DACVU */ -#define WM8983_DACLVOL_MASK 0x00FF /* DACLVOL - [7:0] */ -#define WM8983_DACLVOL_SHIFT 0 /* DACLVOL - [7:0] */ -#define WM8983_DACLVOL_WIDTH 8 /* DACLVOL - [7:0] */ - -/* - * R12 (0x0C) - Right DAC digital vol - */ -#define WM8983_DACVU 0x0100 /* DACVU */ -#define WM8983_DACVU_MASK 0x0100 /* DACVU */ -#define WM8983_DACVU_SHIFT 8 /* DACVU */ -#define WM8983_DACVU_WIDTH 1 /* DACVU */ -#define WM8983_DACRVOL_MASK 0x00FF /* DACRVOL - [7:0] */ -#define WM8983_DACRVOL_SHIFT 0 /* DACRVOL - [7:0] */ -#define WM8983_DACRVOL_WIDTH 8 /* DACRVOL - [7:0] */ - -/* - * R13 (0x0D) - Jack Detect Control 2 - */ -#define WM8983_JD_EN1_MASK 0x00F0 /* JD_EN1 - [7:4] */ -#define WM8983_JD_EN1_SHIFT 4 /* JD_EN1 - [7:4] */ -#define WM8983_JD_EN1_WIDTH 4 /* JD_EN1 - [7:4] */ -#define WM8983_JD_EN0_MASK 0x000F /* JD_EN0 - [3:0] */ -#define WM8983_JD_EN0_SHIFT 0 /* JD_EN0 - [3:0] */ -#define WM8983_JD_EN0_WIDTH 4 /* JD_EN0 - [3:0] */ - -/* - * R14 (0x0E) - ADC Control - */ -#define WM8983_HPFEN 0x0100 /* HPFEN */ -#define WM8983_HPFEN_MASK 0x0100 /* HPFEN */ -#define WM8983_HPFEN_SHIFT 8 /* HPFEN */ -#define WM8983_HPFEN_WIDTH 1 /* HPFEN */ -#define WM8983_HPFAPP 0x0080 /* HPFAPP */ -#define WM8983_HPFAPP_MASK 0x0080 /* HPFAPP */ -#define WM8983_HPFAPP_SHIFT 7 /* HPFAPP */ -#define WM8983_HPFAPP_WIDTH 1 /* HPFAPP */ -#define WM8983_HPFCUT_MASK 0x0070 /* HPFCUT - [6:4] */ -#define WM8983_HPFCUT_SHIFT 4 /* HPFCUT - [6:4] */ -#define WM8983_HPFCUT_WIDTH 3 /* HPFCUT - [6:4] */ -#define WM8983_ADCOSR128 0x0008 /* ADCOSR128 */ -#define WM8983_ADCOSR128_MASK 0x0008 /* ADCOSR128 */ -#define WM8983_ADCOSR128_SHIFT 3 /* ADCOSR128 */ -#define WM8983_ADCOSR128_WIDTH 1 /* ADCOSR128 */ -#define WM8983_ADCRPOL 0x0002 /* ADCRPOL */ -#define WM8983_ADCRPOL_MASK 0x0002 /* ADCRPOL */ -#define WM8983_ADCRPOL_SHIFT 1 /* ADCRPOL */ -#define WM8983_ADCRPOL_WIDTH 1 /* ADCRPOL */ -#define WM8983_ADCLPOL 0x0001 /* ADCLPOL */ -#define WM8983_ADCLPOL_MASK 0x0001 /* ADCLPOL */ -#define WM8983_ADCLPOL_SHIFT 0 /* ADCLPOL */ -#define WM8983_ADCLPOL_WIDTH 1 /* ADCLPOL */ - -/* - * R15 (0x0F) - Left ADC Digital Vol - */ -#define WM8983_ADCVU 0x0100 /* ADCVU */ -#define WM8983_ADCVU_MASK 0x0100 /* ADCVU */ -#define WM8983_ADCVU_SHIFT 8 /* ADCVU */ -#define WM8983_ADCVU_WIDTH 1 /* ADCVU */ -#define WM8983_ADCLVOL_MASK 0x00FF /* ADCLVOL - [7:0] */ -#define WM8983_ADCLVOL_SHIFT 0 /* ADCLVOL - [7:0] */ -#define WM8983_ADCLVOL_WIDTH 8 /* ADCLVOL - [7:0] */ - -/* - * R16 (0x10) - Right ADC Digital Vol - */ -#define WM8983_ADCVU 0x0100 /* ADCVU */ -#define WM8983_ADCVU_MASK 0x0100 /* ADCVU */ -#define WM8983_ADCVU_SHIFT 8 /* ADCVU */ -#define WM8983_ADCVU_WIDTH 1 /* ADCVU */ -#define WM8983_ADCRVOL_MASK 0x00FF /* ADCRVOL - [7:0] */ -#define WM8983_ADCRVOL_SHIFT 0 /* ADCRVOL - [7:0] */ -#define WM8983_ADCRVOL_WIDTH 8 /* ADCRVOL - [7:0] */ - -/* - * R18 (0x12) - EQ1 - low shelf - */ -#define WM8983_EQ3DMODE 0x0100 /* EQ3DMODE */ -#define WM8983_EQ3DMODE_MASK 0x0100 /* EQ3DMODE */ -#define WM8983_EQ3DMODE_SHIFT 8 /* EQ3DMODE */ -#define WM8983_EQ3DMODE_WIDTH 1 /* EQ3DMODE */ -#define WM8983_EQ1C_MASK 0x0060 /* EQ1C - [6:5] */ -#define WM8983_EQ1C_SHIFT 5 /* EQ1C - [6:5] */ -#define WM8983_EQ1C_WIDTH 2 /* EQ1C - [6:5] */ -#define WM8983_EQ1G_MASK 0x001F /* EQ1G - [4:0] */ -#define WM8983_EQ1G_SHIFT 0 /* EQ1G - [4:0] */ -#define WM8983_EQ1G_WIDTH 5 /* EQ1G - [4:0] */ - -/* - * R19 (0x13) - EQ2 - peak 1 - */ -#define WM8983_EQ2BW 0x0100 /* EQ2BW */ -#define WM8983_EQ2BW_MASK 0x0100 /* EQ2BW */ -#define WM8983_EQ2BW_SHIFT 8 /* EQ2BW */ -#define WM8983_EQ2BW_WIDTH 1 /* EQ2BW */ -#define WM8983_EQ2C_MASK 0x0060 /* EQ2C - [6:5] */ -#define WM8983_EQ2C_SHIFT 5 /* EQ2C - [6:5] */ -#define WM8983_EQ2C_WIDTH 2 /* EQ2C - [6:5] */ -#define WM8983_EQ2G_MASK 0x001F /* EQ2G - [4:0] */ -#define WM8983_EQ2G_SHIFT 0 /* EQ2G - [4:0] */ -#define WM8983_EQ2G_WIDTH 5 /* EQ2G - [4:0] */ - -/* - * R20 (0x14) - EQ3 - peak 2 - */ -#define WM8983_EQ3BW 0x0100 /* EQ3BW */ -#define WM8983_EQ3BW_MASK 0x0100 /* EQ3BW */ -#define WM8983_EQ3BW_SHIFT 8 /* EQ3BW */ -#define WM8983_EQ3BW_WIDTH 1 /* EQ3BW */ -#define WM8983_EQ3C_MASK 0x0060 /* EQ3C - [6:5] */ -#define WM8983_EQ3C_SHIFT 5 /* EQ3C - [6:5] */ -#define WM8983_EQ3C_WIDTH 2 /* EQ3C - [6:5] */ -#define WM8983_EQ3G_MASK 0x001F /* EQ3G - [4:0] */ -#define WM8983_EQ3G_SHIFT 0 /* EQ3G - [4:0] */ -#define WM8983_EQ3G_WIDTH 5 /* EQ3G - [4:0] */ - -/* - * R21 (0x15) - EQ4 - peak 3 - */ -#define WM8983_EQ4BW 0x0100 /* EQ4BW */ -#define WM8983_EQ4BW_MASK 0x0100 /* EQ4BW */ -#define WM8983_EQ4BW_SHIFT 8 /* EQ4BW */ -#define WM8983_EQ4BW_WIDTH 1 /* EQ4BW */ -#define WM8983_EQ4C_MASK 0x0060 /* EQ4C - [6:5] */ -#define WM8983_EQ4C_SHIFT 5 /* EQ4C - [6:5] */ -#define WM8983_EQ4C_WIDTH 2 /* EQ4C - [6:5] */ -#define WM8983_EQ4G_MASK 0x001F /* EQ4G - [4:0] */ -#define WM8983_EQ4G_SHIFT 0 /* EQ4G - [4:0] */ -#define WM8983_EQ4G_WIDTH 5 /* EQ4G - [4:0] */ - -/* - * R22 (0x16) - EQ5 - high shelf - */ -#define WM8983_EQ5C_MASK 0x0060 /* EQ5C - [6:5] */ -#define WM8983_EQ5C_SHIFT 5 /* EQ5C - [6:5] */ -#define WM8983_EQ5C_WIDTH 2 /* EQ5C - [6:5] */ -#define WM8983_EQ5G_MASK 0x001F /* EQ5G - [4:0] */ -#define WM8983_EQ5G_SHIFT 0 /* EQ5G - [4:0] */ -#define WM8983_EQ5G_WIDTH 5 /* EQ5G - [4:0] */ - -/* - * R24 (0x18) - DAC Limiter 1 - */ -#define WM8983_LIMEN 0x0100 /* LIMEN */ -#define WM8983_LIMEN_MASK 0x0100 /* LIMEN */ -#define WM8983_LIMEN_SHIFT 8 /* LIMEN */ -#define WM8983_LIMEN_WIDTH 1 /* LIMEN */ -#define WM8983_LIMDCY_MASK 0x00F0 /* LIMDCY - [7:4] */ -#define WM8983_LIMDCY_SHIFT 4 /* LIMDCY - [7:4] */ -#define WM8983_LIMDCY_WIDTH 4 /* LIMDCY - [7:4] */ -#define WM8983_LIMATK_MASK 0x000F /* LIMATK - [3:0] */ -#define WM8983_LIMATK_SHIFT 0 /* LIMATK - [3:0] */ -#define WM8983_LIMATK_WIDTH 4 /* LIMATK - [3:0] */ - -/* - * R25 (0x19) - DAC Limiter 2 - */ -#define WM8983_LIMLVL_MASK 0x0070 /* LIMLVL - [6:4] */ -#define WM8983_LIMLVL_SHIFT 4 /* LIMLVL - [6:4] */ -#define WM8983_LIMLVL_WIDTH 3 /* LIMLVL - [6:4] */ -#define WM8983_LIMBOOST_MASK 0x000F /* LIMBOOST - [3:0] */ -#define WM8983_LIMBOOST_SHIFT 0 /* LIMBOOST - [3:0] */ -#define WM8983_LIMBOOST_WIDTH 4 /* LIMBOOST - [3:0] */ - -/* - * R27 (0x1B) - Notch Filter 1 - */ -#define WM8983_NFU 0x0100 /* NFU */ -#define WM8983_NFU_MASK 0x0100 /* NFU */ -#define WM8983_NFU_SHIFT 8 /* NFU */ -#define WM8983_NFU_WIDTH 1 /* NFU */ -#define WM8983_NFEN 0x0080 /* NFEN */ -#define WM8983_NFEN_MASK 0x0080 /* NFEN */ -#define WM8983_NFEN_SHIFT 7 /* NFEN */ -#define WM8983_NFEN_WIDTH 1 /* NFEN */ -#define WM8983_NFA0_13_7_MASK 0x007F /* NFA0(13:7) - [6:0] */ -#define WM8983_NFA0_13_7_SHIFT 0 /* NFA0(13:7) - [6:0] */ -#define WM8983_NFA0_13_7_WIDTH 7 /* NFA0(13:7) - [6:0] */ - -/* - * R28 (0x1C) - Notch Filter 2 - */ -#define WM8983_NFU 0x0100 /* NFU */ -#define WM8983_NFU_MASK 0x0100 /* NFU */ -#define WM8983_NFU_SHIFT 8 /* NFU */ -#define WM8983_NFU_WIDTH 1 /* NFU */ -#define WM8983_NFA0_6_0_MASK 0x007F /* NFA0(6:0) - [6:0] */ -#define WM8983_NFA0_6_0_SHIFT 0 /* NFA0(6:0) - [6:0] */ -#define WM8983_NFA0_6_0_WIDTH 7 /* NFA0(6:0) - [6:0] */ - -/* - * R29 (0x1D) - Notch Filter 3 - */ -#define WM8983_NFU 0x0100 /* NFU */ -#define WM8983_NFU_MASK 0x0100 /* NFU */ -#define WM8983_NFU_SHIFT 8 /* NFU */ -#define WM8983_NFU_WIDTH 1 /* NFU */ -#define WM8983_NFA1_13_7_MASK 0x007F /* NFA1(13:7) - [6:0] */ -#define WM8983_NFA1_13_7_SHIFT 0 /* NFA1(13:7) - [6:0] */ -#define WM8983_NFA1_13_7_WIDTH 7 /* NFA1(13:7) - [6:0] */ - -/* - * R30 (0x1E) - Notch Filter 4 - */ -#define WM8983_NFU 0x0100 /* NFU */ -#define WM8983_NFU_MASK 0x0100 /* NFU */ -#define WM8983_NFU_SHIFT 8 /* NFU */ -#define WM8983_NFU_WIDTH 1 /* NFU */ -#define WM8983_NFA1_6_0_MASK 0x007F /* NFA1(6:0) - [6:0] */ -#define WM8983_NFA1_6_0_SHIFT 0 /* NFA1(6:0) - [6:0] */ -#define WM8983_NFA1_6_0_WIDTH 7 /* NFA1(6:0) - [6:0] */ - -/* - * R32 (0x20) - ALC control 1 - */ -#define WM8983_ALCSEL_MASK 0x0180 /* ALCSEL - [8:7] */ -#define WM8983_ALCSEL_SHIFT 7 /* ALCSEL - [8:7] */ -#define WM8983_ALCSEL_WIDTH 2 /* ALCSEL - [8:7] */ -#define WM8983_ALCMAX_MASK 0x0038 /* ALCMAX - [5:3] */ -#define WM8983_ALCMAX_SHIFT 3 /* ALCMAX - [5:3] */ -#define WM8983_ALCMAX_WIDTH 3 /* ALCMAX - [5:3] */ -#define WM8983_ALCMIN_MASK 0x0007 /* ALCMIN - [2:0] */ -#define WM8983_ALCMIN_SHIFT 0 /* ALCMIN - [2:0] */ -#define WM8983_ALCMIN_WIDTH 3 /* ALCMIN - [2:0] */ - -/* - * R33 (0x21) - ALC control 2 - */ -#define WM8983_ALCHLD_MASK 0x00F0 /* ALCHLD - [7:4] */ -#define WM8983_ALCHLD_SHIFT 4 /* ALCHLD - [7:4] */ -#define WM8983_ALCHLD_WIDTH 4 /* ALCHLD - [7:4] */ -#define WM8983_ALCLVL_MASK 0x000F /* ALCLVL - [3:0] */ -#define WM8983_ALCLVL_SHIFT 0 /* ALCLVL - [3:0] */ -#define WM8983_ALCLVL_WIDTH 4 /* ALCLVL - [3:0] */ - -/* - * R34 (0x22) - ALC control 3 - */ -#define WM8983_ALCMODE 0x0100 /* ALCMODE */ -#define WM8983_ALCMODE_MASK 0x0100 /* ALCMODE */ -#define WM8983_ALCMODE_SHIFT 8 /* ALCMODE */ -#define WM8983_ALCMODE_WIDTH 1 /* ALCMODE */ -#define WM8983_ALCDCY_MASK 0x00F0 /* ALCDCY - [7:4] */ -#define WM8983_ALCDCY_SHIFT 4 /* ALCDCY - [7:4] */ -#define WM8983_ALCDCY_WIDTH 4 /* ALCDCY - [7:4] */ -#define WM8983_ALCATK_MASK 0x000F /* ALCATK - [3:0] */ -#define WM8983_ALCATK_SHIFT 0 /* ALCATK - [3:0] */ -#define WM8983_ALCATK_WIDTH 4 /* ALCATK - [3:0] */ - -/* - * R35 (0x23) - Noise Gate - */ -#define WM8983_NGEN 0x0008 /* NGEN */ -#define WM8983_NGEN_MASK 0x0008 /* NGEN */ -#define WM8983_NGEN_SHIFT 3 /* NGEN */ -#define WM8983_NGEN_WIDTH 1 /* NGEN */ -#define WM8983_NGTH_MASK 0x0007 /* NGTH - [2:0] */ -#define WM8983_NGTH_SHIFT 0 /* NGTH - [2:0] */ -#define WM8983_NGTH_WIDTH 3 /* NGTH - [2:0] */ - -/* - * R36 (0x24) - PLL N - */ -#define WM8983_PLL_PRESCALE 0x0010 /* PLL_PRESCALE */ -#define WM8983_PLL_PRESCALE_MASK 0x0010 /* PLL_PRESCALE */ -#define WM8983_PLL_PRESCALE_SHIFT 4 /* PLL_PRESCALE */ -#define WM8983_PLL_PRESCALE_WIDTH 1 /* PLL_PRESCALE */ -#define WM8983_PLLN_MASK 0x000F /* PLLN - [3:0] */ -#define WM8983_PLLN_SHIFT 0 /* PLLN - [3:0] */ -#define WM8983_PLLN_WIDTH 4 /* PLLN - [3:0] */ - -/* - * R37 (0x25) - PLL K 1 - */ -#define WM8983_PLLK_23_18_MASK 0x003F /* PLLK(23:18) - [5:0] */ -#define WM8983_PLLK_23_18_SHIFT 0 /* PLLK(23:18) - [5:0] */ -#define WM8983_PLLK_23_18_WIDTH 6 /* PLLK(23:18) - [5:0] */ - -/* - * R38 (0x26) - PLL K 2 - */ -#define WM8983_PLLK_17_9_MASK 0x01FF /* PLLK(17:9) - [8:0] */ -#define WM8983_PLLK_17_9_SHIFT 0 /* PLLK(17:9) - [8:0] */ -#define WM8983_PLLK_17_9_WIDTH 9 /* PLLK(17:9) - [8:0] */ - -/* - * R39 (0x27) - PLL K 3 - */ -#define WM8983_PLLK_8_0_MASK 0x01FF /* PLLK(8:0) - [8:0] */ -#define WM8983_PLLK_8_0_SHIFT 0 /* PLLK(8:0) - [8:0] */ -#define WM8983_PLLK_8_0_WIDTH 9 /* PLLK(8:0) - [8:0] */ - -/* - * R41 (0x29) - 3D control - */ -#define WM8983_DEPTH3D_MASK 0x000F /* DEPTH3D - [3:0] */ -#define WM8983_DEPTH3D_SHIFT 0 /* DEPTH3D - [3:0] */ -#define WM8983_DEPTH3D_WIDTH 4 /* DEPTH3D - [3:0] */ - -/* - * R42 (0x2A) - OUT4 to ADC - */ -#define WM8983_OUT4_2ADCVOL_MASK 0x01C0 /* OUT4_2ADCVOL - [8:6] */ -#define WM8983_OUT4_2ADCVOL_SHIFT 6 /* OUT4_2ADCVOL - [8:6] */ -#define WM8983_OUT4_2ADCVOL_WIDTH 3 /* OUT4_2ADCVOL - [8:6] */ -#define WM8983_OUT4_2LNR 0x0020 /* OUT4_2LNR */ -#define WM8983_OUT4_2LNR_MASK 0x0020 /* OUT4_2LNR */ -#define WM8983_OUT4_2LNR_SHIFT 5 /* OUT4_2LNR */ -#define WM8983_OUT4_2LNR_WIDTH 1 /* OUT4_2LNR */ -#define WM8983_POBCTRL 0x0004 /* POBCTRL */ -#define WM8983_POBCTRL_MASK 0x0004 /* POBCTRL */ -#define WM8983_POBCTRL_SHIFT 2 /* POBCTRL */ -#define WM8983_POBCTRL_WIDTH 1 /* POBCTRL */ -#define WM8983_DELEN 0x0002 /* DELEN */ -#define WM8983_DELEN_MASK 0x0002 /* DELEN */ -#define WM8983_DELEN_SHIFT 1 /* DELEN */ -#define WM8983_DELEN_WIDTH 1 /* DELEN */ -#define WM8983_OUT1DEL 0x0001 /* OUT1DEL */ -#define WM8983_OUT1DEL_MASK 0x0001 /* OUT1DEL */ -#define WM8983_OUT1DEL_SHIFT 0 /* OUT1DEL */ -#define WM8983_OUT1DEL_WIDTH 1 /* OUT1DEL */ - -/* - * R43 (0x2B) - Beep control - */ -#define WM8983_BYPL2RMIX 0x0100 /* BYPL2RMIX */ -#define WM8983_BYPL2RMIX_MASK 0x0100 /* BYPL2RMIX */ -#define WM8983_BYPL2RMIX_SHIFT 8 /* BYPL2RMIX */ -#define WM8983_BYPL2RMIX_WIDTH 1 /* BYPL2RMIX */ -#define WM8983_BYPR2LMIX 0x0080 /* BYPR2LMIX */ -#define WM8983_BYPR2LMIX_MASK 0x0080 /* BYPR2LMIX */ -#define WM8983_BYPR2LMIX_SHIFT 7 /* BYPR2LMIX */ -#define WM8983_BYPR2LMIX_WIDTH 1 /* BYPR2LMIX */ -#define WM8983_MUTERPGA2INV 0x0020 /* MUTERPGA2INV */ -#define WM8983_MUTERPGA2INV_MASK 0x0020 /* MUTERPGA2INV */ -#define WM8983_MUTERPGA2INV_SHIFT 5 /* MUTERPGA2INV */ -#define WM8983_MUTERPGA2INV_WIDTH 1 /* MUTERPGA2INV */ -#define WM8983_INVROUT2 0x0010 /* INVROUT2 */ -#define WM8983_INVROUT2_MASK 0x0010 /* INVROUT2 */ -#define WM8983_INVROUT2_SHIFT 4 /* INVROUT2 */ -#define WM8983_INVROUT2_WIDTH 1 /* INVROUT2 */ -#define WM8983_BEEPVOL_MASK 0x000E /* BEEPVOL - [3:1] */ -#define WM8983_BEEPVOL_SHIFT 1 /* BEEPVOL - [3:1] */ -#define WM8983_BEEPVOL_WIDTH 3 /* BEEPVOL - [3:1] */ -#define WM8983_BEEPEN 0x0001 /* BEEPEN */ -#define WM8983_BEEPEN_MASK 0x0001 /* BEEPEN */ -#define WM8983_BEEPEN_SHIFT 0 /* BEEPEN */ -#define WM8983_BEEPEN_WIDTH 1 /* BEEPEN */ - -/* - * R44 (0x2C) - Input ctrl - */ -#define WM8983_MBVSEL 0x0100 /* MBVSEL */ -#define WM8983_MBVSEL_MASK 0x0100 /* MBVSEL */ -#define WM8983_MBVSEL_SHIFT 8 /* MBVSEL */ -#define WM8983_MBVSEL_WIDTH 1 /* MBVSEL */ -#define WM8983_R2_2INPPGA 0x0040 /* R2_2INPPGA */ -#define WM8983_R2_2INPPGA_MASK 0x0040 /* R2_2INPPGA */ -#define WM8983_R2_2INPPGA_SHIFT 6 /* R2_2INPPGA */ -#define WM8983_R2_2INPPGA_WIDTH 1 /* R2_2INPPGA */ -#define WM8983_RIN2INPPGA 0x0020 /* RIN2INPPGA */ -#define WM8983_RIN2INPPGA_MASK 0x0020 /* RIN2INPPGA */ -#define WM8983_RIN2INPPGA_SHIFT 5 /* RIN2INPPGA */ -#define WM8983_RIN2INPPGA_WIDTH 1 /* RIN2INPPGA */ -#define WM8983_RIP2INPPGA 0x0010 /* RIP2INPPGA */ -#define WM8983_RIP2INPPGA_MASK 0x0010 /* RIP2INPPGA */ -#define WM8983_RIP2INPPGA_SHIFT 4 /* RIP2INPPGA */ -#define WM8983_RIP2INPPGA_WIDTH 1 /* RIP2INPPGA */ -#define WM8983_L2_2INPPGA 0x0004 /* L2_2INPPGA */ -#define WM8983_L2_2INPPGA_MASK 0x0004 /* L2_2INPPGA */ -#define WM8983_L2_2INPPGA_SHIFT 2 /* L2_2INPPGA */ -#define WM8983_L2_2INPPGA_WIDTH 1 /* L2_2INPPGA */ -#define WM8983_LIN2INPPGA 0x0002 /* LIN2INPPGA */ -#define WM8983_LIN2INPPGA_MASK 0x0002 /* LIN2INPPGA */ -#define WM8983_LIN2INPPGA_SHIFT 1 /* LIN2INPPGA */ -#define WM8983_LIN2INPPGA_WIDTH 1 /* LIN2INPPGA */ -#define WM8983_LIP2INPPGA 0x0001 /* LIP2INPPGA */ -#define WM8983_LIP2INPPGA_MASK 0x0001 /* LIP2INPPGA */ -#define WM8983_LIP2INPPGA_SHIFT 0 /* LIP2INPPGA */ -#define WM8983_LIP2INPPGA_WIDTH 1 /* LIP2INPPGA */ - -/* - * R45 (0x2D) - Left INP PGA gain ctrl - */ -#define WM8983_INPGAVU 0x0100 /* INPGAVU */ -#define WM8983_INPGAVU_MASK 0x0100 /* INPGAVU */ -#define WM8983_INPGAVU_SHIFT 8 /* INPGAVU */ -#define WM8983_INPGAVU_WIDTH 1 /* INPGAVU */ -#define WM8983_INPPGAZCL 0x0080 /* INPPGAZCL */ -#define WM8983_INPPGAZCL_MASK 0x0080 /* INPPGAZCL */ -#define WM8983_INPPGAZCL_SHIFT 7 /* INPPGAZCL */ -#define WM8983_INPPGAZCL_WIDTH 1 /* INPPGAZCL */ -#define WM8983_INPPGAMUTEL 0x0040 /* INPPGAMUTEL */ -#define WM8983_INPPGAMUTEL_MASK 0x0040 /* INPPGAMUTEL */ -#define WM8983_INPPGAMUTEL_SHIFT 6 /* INPPGAMUTEL */ -#define WM8983_INPPGAMUTEL_WIDTH 1 /* INPPGAMUTEL */ -#define WM8983_INPPGAVOLL_MASK 0x003F /* INPPGAVOLL - [5:0] */ -#define WM8983_INPPGAVOLL_SHIFT 0 /* INPPGAVOLL - [5:0] */ -#define WM8983_INPPGAVOLL_WIDTH 6 /* INPPGAVOLL - [5:0] */ - -/* - * R46 (0x2E) - Right INP PGA gain ctrl - */ -#define WM8983_INPGAVU 0x0100 /* INPGAVU */ -#define WM8983_INPGAVU_MASK 0x0100 /* INPGAVU */ -#define WM8983_INPGAVU_SHIFT 8 /* INPGAVU */ -#define WM8983_INPGAVU_WIDTH 1 /* INPGAVU */ -#define WM8983_INPPGAZCR 0x0080 /* INPPGAZCR */ -#define WM8983_INPPGAZCR_MASK 0x0080 /* INPPGAZCR */ -#define WM8983_INPPGAZCR_SHIFT 7 /* INPPGAZCR */ -#define WM8983_INPPGAZCR_WIDTH 1 /* INPPGAZCR */ -#define WM8983_INPPGAMUTER 0x0040 /* INPPGAMUTER */ -#define WM8983_INPPGAMUTER_MASK 0x0040 /* INPPGAMUTER */ -#define WM8983_INPPGAMUTER_SHIFT 6 /* INPPGAMUTER */ -#define WM8983_INPPGAMUTER_WIDTH 1 /* INPPGAMUTER */ -#define WM8983_INPPGAVOLR_MASK 0x003F /* INPPGAVOLR - [5:0] */ -#define WM8983_INPPGAVOLR_SHIFT 0 /* INPPGAVOLR - [5:0] */ -#define WM8983_INPPGAVOLR_WIDTH 6 /* INPPGAVOLR - [5:0] */ - -/* - * R47 (0x2F) - Left ADC BOOST ctrl - */ -#define WM8983_PGABOOSTL 0x0100 /* PGABOOSTL */ -#define WM8983_PGABOOSTL_MASK 0x0100 /* PGABOOSTL */ -#define WM8983_PGABOOSTL_SHIFT 8 /* PGABOOSTL */ -#define WM8983_PGABOOSTL_WIDTH 1 /* PGABOOSTL */ -#define WM8983_L2_2BOOSTVOL_MASK 0x0070 /* L2_2BOOSTVOL - [6:4] */ -#define WM8983_L2_2BOOSTVOL_SHIFT 4 /* L2_2BOOSTVOL - [6:4] */ -#define WM8983_L2_2BOOSTVOL_WIDTH 3 /* L2_2BOOSTVOL - [6:4] */ -#define WM8983_AUXL2BOOSTVOL_MASK 0x0007 /* AUXL2BOOSTVOL - [2:0] */ -#define WM8983_AUXL2BOOSTVOL_SHIFT 0 /* AUXL2BOOSTVOL - [2:0] */ -#define WM8983_AUXL2BOOSTVOL_WIDTH 3 /* AUXL2BOOSTVOL - [2:0] */ - -/* - * R48 (0x30) - Right ADC BOOST ctrl - */ -#define WM8983_PGABOOSTR 0x0100 /* PGABOOSTR */ -#define WM8983_PGABOOSTR_MASK 0x0100 /* PGABOOSTR */ -#define WM8983_PGABOOSTR_SHIFT 8 /* PGABOOSTR */ -#define WM8983_PGABOOSTR_WIDTH 1 /* PGABOOSTR */ -#define WM8983_R2_2BOOSTVOL_MASK 0x0070 /* R2_2BOOSTVOL - [6:4] */ -#define WM8983_R2_2BOOSTVOL_SHIFT 4 /* R2_2BOOSTVOL - [6:4] */ -#define WM8983_R2_2BOOSTVOL_WIDTH 3 /* R2_2BOOSTVOL - [6:4] */ -#define WM8983_AUXR2BOOSTVOL_MASK 0x0007 /* AUXR2BOOSTVOL - [2:0] */ -#define WM8983_AUXR2BOOSTVOL_SHIFT 0 /* AUXR2BOOSTVOL - [2:0] */ -#define WM8983_AUXR2BOOSTVOL_WIDTH 3 /* AUXR2BOOSTVOL - [2:0] */ - -/* - * R49 (0x31) - Output ctrl - */ -#define WM8983_DACL2RMIX 0x0040 /* DACL2RMIX */ -#define WM8983_DACL2RMIX_MASK 0x0040 /* DACL2RMIX */ -#define WM8983_DACL2RMIX_SHIFT 6 /* DACL2RMIX */ -#define WM8983_DACL2RMIX_WIDTH 1 /* DACL2RMIX */ -#define WM8983_DACR2LMIX 0x0020 /* DACR2LMIX */ -#define WM8983_DACR2LMIX_MASK 0x0020 /* DACR2LMIX */ -#define WM8983_DACR2LMIX_SHIFT 5 /* DACR2LMIX */ -#define WM8983_DACR2LMIX_WIDTH 1 /* DACR2LMIX */ -#define WM8983_OUT4BOOST 0x0010 /* OUT4BOOST */ -#define WM8983_OUT4BOOST_MASK 0x0010 /* OUT4BOOST */ -#define WM8983_OUT4BOOST_SHIFT 4 /* OUT4BOOST */ -#define WM8983_OUT4BOOST_WIDTH 1 /* OUT4BOOST */ -#define WM8983_OUT3BOOST 0x0008 /* OUT3BOOST */ -#define WM8983_OUT3BOOST_MASK 0x0008 /* OUT3BOOST */ -#define WM8983_OUT3BOOST_SHIFT 3 /* OUT3BOOST */ -#define WM8983_OUT3BOOST_WIDTH 1 /* OUT3BOOST */ -#define WM8983_SPKBOOST 0x0004 /* SPKBOOST */ -#define WM8983_SPKBOOST_MASK 0x0004 /* SPKBOOST */ -#define WM8983_SPKBOOST_SHIFT 2 /* SPKBOOST */ -#define WM8983_SPKBOOST_WIDTH 1 /* SPKBOOST */ -#define WM8983_TSDEN 0x0002 /* TSDEN */ -#define WM8983_TSDEN_MASK 0x0002 /* TSDEN */ -#define WM8983_TSDEN_SHIFT 1 /* TSDEN */ -#define WM8983_TSDEN_WIDTH 1 /* TSDEN */ -#define WM8983_VROI 0x0001 /* VROI */ -#define WM8983_VROI_MASK 0x0001 /* VROI */ -#define WM8983_VROI_SHIFT 0 /* VROI */ -#define WM8983_VROI_WIDTH 1 /* VROI */ - -/* - * R50 (0x32) - Left mixer ctrl - */ -#define WM8983_AUXLMIXVOL_MASK 0x01C0 /* AUXLMIXVOL - [8:6] */ -#define WM8983_AUXLMIXVOL_SHIFT 6 /* AUXLMIXVOL - [8:6] */ -#define WM8983_AUXLMIXVOL_WIDTH 3 /* AUXLMIXVOL - [8:6] */ -#define WM8983_AUXL2LMIX 0x0020 /* AUXL2LMIX */ -#define WM8983_AUXL2LMIX_MASK 0x0020 /* AUXL2LMIX */ -#define WM8983_AUXL2LMIX_SHIFT 5 /* AUXL2LMIX */ -#define WM8983_AUXL2LMIX_WIDTH 1 /* AUXL2LMIX */ -#define WM8983_BYPLMIXVOL_MASK 0x001C /* BYPLMIXVOL - [4:2] */ -#define WM8983_BYPLMIXVOL_SHIFT 2 /* BYPLMIXVOL - [4:2] */ -#define WM8983_BYPLMIXVOL_WIDTH 3 /* BYPLMIXVOL - [4:2] */ -#define WM8983_BYPL2LMIX 0x0002 /* BYPL2LMIX */ -#define WM8983_BYPL2LMIX_MASK 0x0002 /* BYPL2LMIX */ -#define WM8983_BYPL2LMIX_SHIFT 1 /* BYPL2LMIX */ -#define WM8983_BYPL2LMIX_WIDTH 1 /* BYPL2LMIX */ -#define WM8983_DACL2LMIX 0x0001 /* DACL2LMIX */ -#define WM8983_DACL2LMIX_MASK 0x0001 /* DACL2LMIX */ -#define WM8983_DACL2LMIX_SHIFT 0 /* DACL2LMIX */ -#define WM8983_DACL2LMIX_WIDTH 1 /* DACL2LMIX */ - -/* - * R51 (0x33) - Right mixer ctrl - */ -#define WM8983_AUXRMIXVOL_MASK 0x01C0 /* AUXRMIXVOL - [8:6] */ -#define WM8983_AUXRMIXVOL_SHIFT 6 /* AUXRMIXVOL - [8:6] */ -#define WM8983_AUXRMIXVOL_WIDTH 3 /* AUXRMIXVOL - [8:6] */ -#define WM8983_AUXR2RMIX 0x0020 /* AUXR2RMIX */ -#define WM8983_AUXR2RMIX_MASK 0x0020 /* AUXR2RMIX */ -#define WM8983_AUXR2RMIX_SHIFT 5 /* AUXR2RMIX */ -#define WM8983_AUXR2RMIX_WIDTH 1 /* AUXR2RMIX */ -#define WM8983_BYPRMIXVOL_MASK 0x001C /* BYPRMIXVOL - [4:2] */ -#define WM8983_BYPRMIXVOL_SHIFT 2 /* BYPRMIXVOL - [4:2] */ -#define WM8983_BYPRMIXVOL_WIDTH 3 /* BYPRMIXVOL - [4:2] */ -#define WM8983_BYPR2RMIX 0x0002 /* BYPR2RMIX */ -#define WM8983_BYPR2RMIX_MASK 0x0002 /* BYPR2RMIX */ -#define WM8983_BYPR2RMIX_SHIFT 1 /* BYPR2RMIX */ -#define WM8983_BYPR2RMIX_WIDTH 1 /* BYPR2RMIX */ -#define WM8983_DACR2RMIX 0x0001 /* DACR2RMIX */ -#define WM8983_DACR2RMIX_MASK 0x0001 /* DACR2RMIX */ -#define WM8983_DACR2RMIX_SHIFT 0 /* DACR2RMIX */ -#define WM8983_DACR2RMIX_WIDTH 1 /* DACR2RMIX */ - -/* - * R52 (0x34) - LOUT1 (HP) volume ctrl - */ -#define WM8983_OUT1VU 0x0100 /* OUT1VU */ -#define WM8983_OUT1VU_MASK 0x0100 /* OUT1VU */ -#define WM8983_OUT1VU_SHIFT 8 /* OUT1VU */ -#define WM8983_OUT1VU_WIDTH 1 /* OUT1VU */ -#define WM8983_LOUT1ZC 0x0080 /* LOUT1ZC */ -#define WM8983_LOUT1ZC_MASK 0x0080 /* LOUT1ZC */ -#define WM8983_LOUT1ZC_SHIFT 7 /* LOUT1ZC */ -#define WM8983_LOUT1ZC_WIDTH 1 /* LOUT1ZC */ -#define WM8983_LOUT1MUTE 0x0040 /* LOUT1MUTE */ -#define WM8983_LOUT1MUTE_MASK 0x0040 /* LOUT1MUTE */ -#define WM8983_LOUT1MUTE_SHIFT 6 /* LOUT1MUTE */ -#define WM8983_LOUT1MUTE_WIDTH 1 /* LOUT1MUTE */ -#define WM8983_LOUT1VOL_MASK 0x003F /* LOUT1VOL - [5:0] */ -#define WM8983_LOUT1VOL_SHIFT 0 /* LOUT1VOL - [5:0] */ -#define WM8983_LOUT1VOL_WIDTH 6 /* LOUT1VOL - [5:0] */ - -/* - * R53 (0x35) - ROUT1 (HP) volume ctrl - */ -#define WM8983_OUT1VU 0x0100 /* OUT1VU */ -#define WM8983_OUT1VU_MASK 0x0100 /* OUT1VU */ -#define WM8983_OUT1VU_SHIFT 8 /* OUT1VU */ -#define WM8983_OUT1VU_WIDTH 1 /* OUT1VU */ -#define WM8983_ROUT1ZC 0x0080 /* ROUT1ZC */ -#define WM8983_ROUT1ZC_MASK 0x0080 /* ROUT1ZC */ -#define WM8983_ROUT1ZC_SHIFT 7 /* ROUT1ZC */ -#define WM8983_ROUT1ZC_WIDTH 1 /* ROUT1ZC */ -#define WM8983_ROUT1MUTE 0x0040 /* ROUT1MUTE */ -#define WM8983_ROUT1MUTE_MASK 0x0040 /* ROUT1MUTE */ -#define WM8983_ROUT1MUTE_SHIFT 6 /* ROUT1MUTE */ -#define WM8983_ROUT1MUTE_WIDTH 1 /* ROUT1MUTE */ -#define WM8983_ROUT1VOL_MASK 0x003F /* ROUT1VOL - [5:0] */ -#define WM8983_ROUT1VOL_SHIFT 0 /* ROUT1VOL - [5:0] */ -#define WM8983_ROUT1VOL_WIDTH 6 /* ROUT1VOL - [5:0] */ - -/* - * R54 (0x36) - LOUT2 (SPK) volume ctrl - */ -#define WM8983_OUT2VU 0x0100 /* OUT2VU */ -#define WM8983_OUT2VU_MASK 0x0100 /* OUT2VU */ -#define WM8983_OUT2VU_SHIFT 8 /* OUT2VU */ -#define WM8983_OUT2VU_WIDTH 1 /* OUT2VU */ -#define WM8983_LOUT2ZC 0x0080 /* LOUT2ZC */ -#define WM8983_LOUT2ZC_MASK 0x0080 /* LOUT2ZC */ -#define WM8983_LOUT2ZC_SHIFT 7 /* LOUT2ZC */ -#define WM8983_LOUT2ZC_WIDTH 1 /* LOUT2ZC */ -#define WM8983_LOUT2MUTE 0x0040 /* LOUT2MUTE */ -#define WM8983_LOUT2MUTE_MASK 0x0040 /* LOUT2MUTE */ -#define WM8983_LOUT2MUTE_SHIFT 6 /* LOUT2MUTE */ -#define WM8983_LOUT2MUTE_WIDTH 1 /* LOUT2MUTE */ -#define WM8983_LOUT2VOL_MASK 0x003F /* LOUT2VOL - [5:0] */ -#define WM8983_LOUT2VOL_SHIFT 0 /* LOUT2VOL - [5:0] */ -#define WM8983_LOUT2VOL_WIDTH 6 /* LOUT2VOL - [5:0] */ - -/* - * R55 (0x37) - ROUT2 (SPK) volume ctrl - */ -#define WM8983_OUT2VU 0x0100 /* OUT2VU */ -#define WM8983_OUT2VU_MASK 0x0100 /* OUT2VU */ -#define WM8983_OUT2VU_SHIFT 8 /* OUT2VU */ -#define WM8983_OUT2VU_WIDTH 1 /* OUT2VU */ -#define WM8983_ROUT2ZC 0x0080 /* ROUT2ZC */ -#define WM8983_ROUT2ZC_MASK 0x0080 /* ROUT2ZC */ -#define WM8983_ROUT2ZC_SHIFT 7 /* ROUT2ZC */ -#define WM8983_ROUT2ZC_WIDTH 1 /* ROUT2ZC */ -#define WM8983_ROUT2MUTE 0x0040 /* ROUT2MUTE */ -#define WM8983_ROUT2MUTE_MASK 0x0040 /* ROUT2MUTE */ -#define WM8983_ROUT2MUTE_SHIFT 6 /* ROUT2MUTE */ -#define WM8983_ROUT2MUTE_WIDTH 1 /* ROUT2MUTE */ -#define WM8983_ROUT2VOL_MASK 0x003F /* ROUT2VOL - [5:0] */ -#define WM8983_ROUT2VOL_SHIFT 0 /* ROUT2VOL - [5:0] */ -#define WM8983_ROUT2VOL_WIDTH 6 /* ROUT2VOL - [5:0] */ - -/* - * R56 (0x38) - OUT3 mixer ctrl - */ -#define WM8983_OUT3MUTE 0x0040 /* OUT3MUTE */ -#define WM8983_OUT3MUTE_MASK 0x0040 /* OUT3MUTE */ -#define WM8983_OUT3MUTE_SHIFT 6 /* OUT3MUTE */ -#define WM8983_OUT3MUTE_WIDTH 1 /* OUT3MUTE */ -#define WM8983_OUT4_2OUT3 0x0008 /* OUT4_2OUT3 */ -#define WM8983_OUT4_2OUT3_MASK 0x0008 /* OUT4_2OUT3 */ -#define WM8983_OUT4_2OUT3_SHIFT 3 /* OUT4_2OUT3 */ -#define WM8983_OUT4_2OUT3_WIDTH 1 /* OUT4_2OUT3 */ -#define WM8983_BYPL2OUT3 0x0004 /* BYPL2OUT3 */ -#define WM8983_BYPL2OUT3_MASK 0x0004 /* BYPL2OUT3 */ -#define WM8983_BYPL2OUT3_SHIFT 2 /* BYPL2OUT3 */ -#define WM8983_BYPL2OUT3_WIDTH 1 /* BYPL2OUT3 */ -#define WM8983_LMIX2OUT3 0x0002 /* LMIX2OUT3 */ -#define WM8983_LMIX2OUT3_MASK 0x0002 /* LMIX2OUT3 */ -#define WM8983_LMIX2OUT3_SHIFT 1 /* LMIX2OUT3 */ -#define WM8983_LMIX2OUT3_WIDTH 1 /* LMIX2OUT3 */ -#define WM8983_LDAC2OUT3 0x0001 /* LDAC2OUT3 */ -#define WM8983_LDAC2OUT3_MASK 0x0001 /* LDAC2OUT3 */ -#define WM8983_LDAC2OUT3_SHIFT 0 /* LDAC2OUT3 */ -#define WM8983_LDAC2OUT3_WIDTH 1 /* LDAC2OUT3 */ - -/* - * R57 (0x39) - OUT4 (MONO) mix ctrl - */ -#define WM8983_OUT3_2OUT4 0x0080 /* OUT3_2OUT4 */ -#define WM8983_OUT3_2OUT4_MASK 0x0080 /* OUT3_2OUT4 */ -#define WM8983_OUT3_2OUT4_SHIFT 7 /* OUT3_2OUT4 */ -#define WM8983_OUT3_2OUT4_WIDTH 1 /* OUT3_2OUT4 */ -#define WM8983_OUT4MUTE 0x0040 /* OUT4MUTE */ -#define WM8983_OUT4MUTE_MASK 0x0040 /* OUT4MUTE */ -#define WM8983_OUT4MUTE_SHIFT 6 /* OUT4MUTE */ -#define WM8983_OUT4MUTE_WIDTH 1 /* OUT4MUTE */ -#define WM8983_OUT4ATTN 0x0020 /* OUT4ATTN */ -#define WM8983_OUT4ATTN_MASK 0x0020 /* OUT4ATTN */ -#define WM8983_OUT4ATTN_SHIFT 5 /* OUT4ATTN */ -#define WM8983_OUT4ATTN_WIDTH 1 /* OUT4ATTN */ -#define WM8983_LMIX2OUT4 0x0010 /* LMIX2OUT4 */ -#define WM8983_LMIX2OUT4_MASK 0x0010 /* LMIX2OUT4 */ -#define WM8983_LMIX2OUT4_SHIFT 4 /* LMIX2OUT4 */ -#define WM8983_LMIX2OUT4_WIDTH 1 /* LMIX2OUT4 */ -#define WM8983_LDAC2OUT4 0x0008 /* LDAC2OUT4 */ -#define WM8983_LDAC2OUT4_MASK 0x0008 /* LDAC2OUT4 */ -#define WM8983_LDAC2OUT4_SHIFT 3 /* LDAC2OUT4 */ -#define WM8983_LDAC2OUT4_WIDTH 1 /* LDAC2OUT4 */ -#define WM8983_BYPR2OUT4 0x0004 /* BYPR2OUT4 */ -#define WM8983_BYPR2OUT4_MASK 0x0004 /* BYPR2OUT4 */ -#define WM8983_BYPR2OUT4_SHIFT 2 /* BYPR2OUT4 */ -#define WM8983_BYPR2OUT4_WIDTH 1 /* BYPR2OUT4 */ -#define WM8983_RMIX2OUT4 0x0002 /* RMIX2OUT4 */ -#define WM8983_RMIX2OUT4_MASK 0x0002 /* RMIX2OUT4 */ -#define WM8983_RMIX2OUT4_SHIFT 1 /* RMIX2OUT4 */ -#define WM8983_RMIX2OUT4_WIDTH 1 /* RMIX2OUT4 */ -#define WM8983_RDAC2OUT4 0x0001 /* RDAC2OUT4 */ -#define WM8983_RDAC2OUT4_MASK 0x0001 /* RDAC2OUT4 */ -#define WM8983_RDAC2OUT4_SHIFT 0 /* RDAC2OUT4 */ -#define WM8983_RDAC2OUT4_WIDTH 1 /* RDAC2OUT4 */ - -/* - * R61 (0x3D) - BIAS CTRL - */ -#define WM8983_BIASCUT 0x0100 /* BIASCUT */ -#define WM8983_BIASCUT_MASK 0x0100 /* BIASCUT */ -#define WM8983_BIASCUT_SHIFT 8 /* BIASCUT */ -#define WM8983_BIASCUT_WIDTH 1 /* BIASCUT */ -#define WM8983_HALFIPBIAS 0x0080 /* HALFIPBIAS */ -#define WM8983_HALFIPBIAS_MASK 0x0080 /* HALFIPBIAS */ -#define WM8983_HALFIPBIAS_SHIFT 7 /* HALFIPBIAS */ -#define WM8983_HALFIPBIAS_WIDTH 1 /* HALFIPBIAS */ -#define WM8983_VBBIASTST_MASK 0x0060 /* VBBIASTST - [6:5] */ -#define WM8983_VBBIASTST_SHIFT 5 /* VBBIASTST - [6:5] */ -#define WM8983_VBBIASTST_WIDTH 2 /* VBBIASTST - [6:5] */ -#define WM8983_BUFBIAS_MASK 0x0018 /* BUFBIAS - [4:3] */ -#define WM8983_BUFBIAS_SHIFT 3 /* BUFBIAS - [4:3] */ -#define WM8983_BUFBIAS_WIDTH 2 /* BUFBIAS - [4:3] */ -#define WM8983_ADCBIAS_MASK 0x0006 /* ADCBIAS - [2:1] */ -#define WM8983_ADCBIAS_SHIFT 1 /* ADCBIAS - [2:1] */ -#define WM8983_ADCBIAS_WIDTH 2 /* ADCBIAS - [2:1] */ -#define WM8983_HALFOPBIAS 0x0001 /* HALFOPBIAS */ -#define WM8983_HALFOPBIAS_MASK 0x0001 /* HALFOPBIAS */ -#define WM8983_HALFOPBIAS_SHIFT 0 /* HALFOPBIAS */ -#define WM8983_HALFOPBIAS_WIDTH 1 /* HALFOPBIAS */ - -enum clk_src { - WM8983_CLKSRC_MCLK, - WM8983_CLKSRC_PLL -}; - -#endif /* _WM8983_H */ diff --git a/trunk/sound/soc/codecs/wm8993.c b/trunk/sound/soc/codecs/wm8993.c index 6e85b8869af7..9e5ff789b805 100644 --- a/trunk/sound/soc/codecs/wm8993.c +++ b/trunk/sound/soc/codecs/wm8993.c @@ -876,7 +876,7 @@ SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0, left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0, right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), -SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), + }; static const struct snd_soc_dapm_route routes[] = { @@ -1434,7 +1434,6 @@ static int wm8993_probe(struct snd_soc_codec *codec) wm8993->hubs_data.hp_startup_mode = 1; wm8993->hubs_data.dcs_codes = -2; - wm8993->hubs_data.series_startup = 1; ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); if (ret != 0) { diff --git a/trunk/sound/soc/codecs/wm8994.c b/trunk/sound/soc/codecs/wm8994.c index 09e680ae88b2..83014a7c2e14 100644 --- a/trunk/sound/soc/codecs/wm8994.c +++ b/trunk/sound/soc/codecs/wm8994.c @@ -195,6 +195,10 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif) aif + 1, rate); } + if (rate && rate < 3000000) + dev_warn(codec->dev, "AIF%dCLK is %dHz, should be >=3MHz for optimal performance\n", + aif + 1, rate); + wm8994->aifclk[aif] = rate; snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset, @@ -1142,33 +1146,13 @@ SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, late_enable_ev, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, late_enable_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_PGA_E("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0, - late_enable_ev, SND_SOC_DAPM_PRE_PMU), - -SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, - left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer), - late_enable_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, - right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer), - late_enable_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux, - late_enable_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux, - late_enable_ev, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev) }; static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = { SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0), -SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), -SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, - left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), -SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, - right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), -SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), -SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), +SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0) }; static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = { @@ -1298,6 +1282,14 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0), SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), +SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), + +SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, + left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), +SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, + right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), + SND_SOC_DAPM_POST("Debug log", post_ev), }; @@ -1632,7 +1624,6 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, int reg_offset, ret; struct fll_div fll; u16 reg, aif1, aif2; - unsigned long timeout; aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) & WM8994_AIF1CLK_ENA; @@ -1714,9 +1705,6 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) | (src - 1)); - /* Clear any pending completion from a previous failure */ - try_wait_for_completion(&wm8994->fll_locked[id]); - /* Enable (with fractional mode if required) */ if (freq_out) { if (fll.k) @@ -1727,15 +1715,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, WM8994_FLL1_ENA | WM8994_FLL1_FRAC, reg); - if (wm8994->fll_locked_irq) { - timeout = wait_for_completion_timeout(&wm8994->fll_locked[id], - msecs_to_jiffies(10)); - if (timeout == 0) - dev_warn(codec->dev, - "Timed out waiting for FLL lock\n"); - } else { - msleep(5); - } + msleep(5); } wm8994->fll[id].in = freq_in; @@ -1753,14 +1733,6 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, return 0; } -static irqreturn_t wm8994_fll_locked_irq(int irq, void *data) -{ - struct completion *completion = data; - - complete(completion); - - return IRQ_HANDLED; -} static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; @@ -2300,33 +2272,6 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream, return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1); } -static void wm8994_aif_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - int rate_reg = 0; - - switch (dai->id) { - case 1: - rate_reg = WM8994_AIF1_RATE; - break; - case 2: - rate_reg = WM8994_AIF1_RATE; - break; - default: - break; - } - - /* If the DAI is idle then configure the divider tree for the - * lowest output rate to save a little power if the clock is - * still active (eg, because it is system clock). - */ - if (rate_reg && !dai->playback_active && !dai->capture_active) - snd_soc_update_bits(codec, rate_reg, - WM8994_AIF1_SR_MASK | - WM8994_AIF1CLK_RATE_MASK, 0x9); -} - static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute) { struct snd_soc_codec *codec = codec_dai->codec; @@ -2393,7 +2338,6 @@ static struct snd_soc_dai_ops wm8994_aif1_dai_ops = { .set_sysclk = wm8994_set_dai_sysclk, .set_fmt = wm8994_set_dai_fmt, .hw_params = wm8994_hw_params, - .shutdown = wm8994_aif_shutdown, .digital_mute = wm8994_aif_mute, .set_pll = wm8994_set_fll, .set_tristate = wm8994_set_tristate, @@ -2403,7 +2347,6 @@ static struct snd_soc_dai_ops wm8994_aif2_dai_ops = { .set_sysclk = wm8994_set_dai_sysclk, .set_fmt = wm8994_set_dai_fmt, .hw_params = wm8994_hw_params, - .shutdown = wm8994_aif_shutdown, .digital_mute = wm8994_aif_mute, .set_pll = wm8994_set_fll, .set_tristate = wm8994_set_tristate, @@ -2907,15 +2850,6 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t wm8994_fifo_error(int irq, void *data) -{ - struct snd_soc_codec *codec = data; - - dev_err(codec->dev, "FIFO error\n"); - - return IRQ_HANDLED; -} - static int wm8994_codec_probe(struct snd_soc_codec *codec) { struct wm8994 *control; @@ -2934,9 +2868,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->pdata = dev_get_platdata(codec->dev->parent); wm8994->codec = codec; - for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) - init_completion(&wm8994->fll_locked[i]); - if (wm8994->pdata && wm8994->pdata->micdet_irq) wm8994->micdet_irq = wm8994->pdata->micdet_irq; else if (wm8994->pdata && wm8994->pdata->irq_base) @@ -2975,7 +2906,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->hubs.dcs_codes = -5; wm8994->hubs.hp_startup_mode = 1; wm8994->hubs.dcs_readback_mode = 1; - wm8994->hubs.series_startup = 1; break; default: wm8994->hubs.dcs_readback_mode = 1; @@ -2990,15 +2920,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) break; } - wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, - wm8994_fifo_error, "FIFO error", codec); - - ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE, - wm_hubs_dcs_done, "DC servo done", - &wm8994->hubs); - if (ret == 0) - wm8994->hubs.dcs_done_irq = true; - switch (control->type) { case WM8994: if (wm8994->micdet_irq) { @@ -3055,16 +2976,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) } } - wm8994->fll_locked_irq = true; - for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) { - ret = wm8994_request_irq(codec->control_data, - WM8994_IRQ_FLL1_LOCK + i, - wm8994_fll_locked_irq, "FLL lock", - &wm8994->fll_locked[i]); - if (ret != 0) - wm8994->fll_locked_irq = false; - } - /* Remember if AIFnLRCLK is configured as a GPIO. This should be * configured on init - if a system wants to do this dynamically * at runtime we can deal with that then. @@ -3140,18 +3051,10 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); - /* Unconditionally enable AIF1 ADC TDM mode on chips which can - * use this; it only affects behaviour on idle TDM clock - * cycles. */ - switch (control->type) { - case WM8994: - case WM8958: - snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, - WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM); - break; - default: - break; - } + /* Unconditionally enable AIF1 ADC TDM mode; it only affects + * behaviour on idle TDM clock cycles. */ + snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, + WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM); wm8994_update_class_w(codec); @@ -3250,12 +3153,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); if (wm8994->micdet_irq) free_irq(wm8994->micdet_irq, wm8994); - for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) - wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i, - &wm8994->fll_locked[i]); - wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE, - &wm8994->hubs); - wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec); err: kfree(wm8994); return ret; @@ -3265,20 +3162,11 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = codec->control_data; - int i; wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); pm_runtime_disable(codec->dev); - for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) - wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i, - &wm8994->fll_locked[i]); - - wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE, - &wm8994->hubs); - wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec); - switch (control->type) { case WM8994: if (wm8994->micdet_irq) diff --git a/trunk/sound/soc/codecs/wm8994.h b/trunk/sound/soc/codecs/wm8994.h index 1ab2266039f7..0a1db04b73bd 100644 --- a/trunk/sound/soc/codecs/wm8994.h +++ b/trunk/sound/soc/codecs/wm8994.h @@ -11,7 +11,6 @@ #include #include -#include #include "wm_hubs.h" @@ -80,8 +79,6 @@ struct wm8994_priv { int mclk[2]; int aifclk[2]; struct wm8994_fll_config fll[2], fll_suspend[2]; - struct completion fll_locked[2]; - bool fll_locked_irq; int dac_rates[2]; int lrclk_shared[2]; diff --git a/trunk/sound/soc/codecs/wm9081.c b/trunk/sound/soc/codecs/wm9081.c index a4691321f9b3..91c6b39de50c 100644 --- a/trunk/sound/soc/codecs/wm9081.c +++ b/trunk/sound/soc/codecs/wm9081.c @@ -727,7 +727,7 @@ SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0), SND_SOC_DAPM_PGA("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0), -SND_SOC_DAPM_OUT_DRV("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0), SND_SOC_DAPM_OUTPUT("LINEOUT"), SND_SOC_DAPM_OUTPUT("SPKN"), diff --git a/trunk/sound/soc/codecs/wm_hubs.c b/trunk/sound/soc/codecs/wm_hubs.c index 4cc2d567f22f..9e370d14ad88 100644 --- a/trunk/sound/soc/codecs/wm_hubs.c +++ b/trunk/sound/soc/codecs/wm_hubs.c @@ -63,10 +63,8 @@ static const struct soc_enum speaker_mode = static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) { - struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); unsigned int reg; int count = 0; - int timeout; unsigned int val; val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1; @@ -76,39 +74,18 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) dev_dbg(codec->dev, "Waiting for DC servo...\n"); - if (hubs->dcs_done_irq) - timeout = 4; - else - timeout = 400; - do { count++; - - if (hubs->dcs_done_irq) - wait_for_completion_timeout(&hubs->dcs_done, - msecs_to_jiffies(250)); - else - msleep(1); - + msleep(1); reg = snd_soc_read(codec, WM8993_DC_SERVO_0); dev_dbg(codec->dev, "DC servo: %x\n", reg); - } while (reg & op && count < timeout); + } while (reg & op && count < 400); if (reg & op) dev_err(codec->dev, "Timed out waiting for DC Servo %x\n", op); } -irqreturn_t wm_hubs_dcs_done(int irq, void *data) -{ - struct wm_hubs_data *hubs = data; - - complete(&hubs->dcs_done); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL_GPL(wm_hubs_dcs_done); - /* * Startup calibration of the DC servo */ @@ -130,7 +107,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) return; } - if (hubs->series_startup) { + /* Devices not using a DCS code correction have startup mode */ + if (hubs->dcs_codes) { /* Set for 32 series updates */ snd_soc_update_bits(codec, WM8993_DC_SERVO_1, WM8993_DCS_SERIES_NO_01_MASK, @@ -156,9 +134,9 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) break; case 1: reg = snd_soc_read(codec, WM8993_DC_SERVO_3); - reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) + reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; - reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; + reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; break; default: WARN(1, "Unknown DCS readback method\n"); @@ -172,13 +150,13 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) dev_dbg(codec->dev, "Applying %d code DC servo correction\n", hubs->dcs_codes); - /* HPOUT1R */ - offset = reg_r; + /* HPOUT1L */ + offset = reg_l; offset += hubs->dcs_codes; dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT; - /* HPOUT1L */ - offset = reg_l; + /* HPOUT1R */ + offset = reg_r; offset += hubs->dcs_codes; dcs_cfg |= (u8)offset; @@ -190,8 +168,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) WM8993_DCS_TRIG_DAC_WR_0 | WM8993_DCS_TRIG_DAC_WR_1); } else { - dcs_cfg = reg_r << WM8993_DCS_DAC_WR_VAL_1_SHIFT; - dcs_cfg |= reg_l; + dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT; + dcs_cfg |= reg_r; } /* Save the callibrated offset if we're in class W mode and @@ -217,7 +195,7 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, /* If we're applying an offset correction then updating the * callibration would be likely to introduce further offsets. */ - if (hubs->dcs_codes || hubs->no_series_update) + if (hubs->dcs_codes) return ret; /* Only need to do this if the outputs are active */ @@ -621,6 +599,9 @@ SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0, SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0, in2r_pga, ARRAY_SIZE(in2r_pga)), +/* Dummy widgets to represent differential paths */ +SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0, mixinl, ARRAY_SIZE(mixinl)), SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, @@ -886,11 +867,8 @@ EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls); int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, int lineout1_diff, int lineout2_diff) { - struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = &codec->dapm; - init_completion(&hubs->dcs_done); - snd_soc_dapm_add_routes(dapm, analogue_routes, ARRAY_SIZE(analogue_routes)); diff --git a/trunk/sound/soc/codecs/wm_hubs.h b/trunk/sound/soc/codecs/wm_hubs.h index 676b1252ab91..f8a5e976b5e6 100644 --- a/trunk/sound/soc/codecs/wm_hubs.h +++ b/trunk/sound/soc/codecs/wm_hubs.h @@ -14,9 +14,6 @@ #ifndef _WM_HUBS_H #define _WM_HUBS_H -#include -#include - struct snd_soc_codec; extern const unsigned int wm_hubs_spkmix_tlv[]; @@ -26,14 +23,9 @@ struct wm_hubs_data { int dcs_codes; int dcs_readback_mode; int hp_startup_mode; - int series_startup; - int no_series_update; bool class_w; u16 class_w_dcs; - - bool dcs_done_irq; - struct completion dcs_done; }; extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); @@ -44,6 +36,4 @@ extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *, int jd_scthr, int jd_thr, int micbias1_lvl, int micbias2_lvl); -extern irqreturn_t wm_hubs_dcs_done(int irq, void *data); - #endif diff --git a/trunk/sound/soc/davinci/davinci-pcm.c b/trunk/sound/soc/davinci/davinci-pcm.c index a49e667373bc..9d35b8c1a624 100644 --- a/trunk/sound/soc/davinci/davinci-pcm.c +++ b/trunk/sound/soc/davinci/davinci-pcm.c @@ -46,28 +46,11 @@ static void print_buf_info(int slot, char *name) } #endif -#define DAVINCI_PCM_FMTBITS (\ - SNDRV_PCM_FMTBIT_S8 |\ - SNDRV_PCM_FMTBIT_U8 |\ - SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_U16_LE |\ - SNDRV_PCM_FMTBIT_U16_BE |\ - SNDRV_PCM_FMTBIT_S24_LE |\ - SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_U24_LE |\ - SNDRV_PCM_FMTBIT_U24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE |\ - SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_U32_LE |\ - SNDRV_PCM_FMTBIT_U32_BE) - static struct snd_pcm_hardware pcm_hardware_playback = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME| - SNDRV_PCM_INFO_BATCH), - .formats = DAVINCI_PCM_FMTBITS, + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), + .formats = (SNDRV_PCM_FMTBIT_S16_LE), .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | @@ -76,7 +59,7 @@ static struct snd_pcm_hardware pcm_hardware_playback = { .rate_min = 8000, .rate_max = 96000, .channels_min = 2, - .channels_max = 384, + .channels_max = 2, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 32, .period_bytes_max = 8 * 1024, @@ -88,9 +71,8 @@ static struct snd_pcm_hardware pcm_hardware_playback = { static struct snd_pcm_hardware pcm_hardware_capture = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH), - .formats = DAVINCI_PCM_FMTBITS, + SNDRV_PCM_INFO_PAUSE), + .formats = (SNDRV_PCM_FMTBIT_S16_LE), .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | @@ -99,7 +81,7 @@ static struct snd_pcm_hardware pcm_hardware_capture = { .rate_min = 8000, .rate_max = 96000, .channels_min = 2, - .channels_max = 384, + .channels_max = 2, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 32, .period_bytes_max = 8 * 1024, @@ -157,22 +139,6 @@ struct davinci_runtime_data { struct edmacc_param ram_params; }; -static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - - prtd->period++; - if (unlikely(prtd->period >= runtime->periods)) - prtd->period = 0; -} - -static void davinci_pcm_period_reset(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - - prtd->period = 0; -} /* * Not used with ping/pong */ @@ -233,6 +199,10 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) else edma_set_transfer_params(link, acnt, fifo_level, count, fifo_level, ABSYNC); + + prtd->period++; + if (unlikely(prtd->period >= runtime->periods)) + prtd->period = 0; } static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) @@ -247,13 +217,12 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) return; if (snd_pcm_running(substream)) { - spin_lock(&prtd->lock); if (prtd->ram_channel < 0) { /* No ping/pong must fix up link dma data*/ + spin_lock(&prtd->lock); davinci_pcm_enqueue_dma(substream); + spin_unlock(&prtd->lock); } - davinci_pcm_period_elapsed(substream); - spin_unlock(&prtd->lock); snd_pcm_period_elapsed(substream); } } @@ -456,8 +425,7 @@ static int request_ping_pong(struct snd_pcm_substream *substream, edma_read_slot(link, &prtd->asp_params); prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN); - prtd->asp_params.opt |= TCCHEN | - EDMA_TCC(prtd->ram_channel & 0x3f); + prtd->asp_params.opt |= TCCHEN | EDMA_TCC(prtd->ram_channel & 0x3f); edma_write_slot(link, &prtd->asp_params); /* pong */ @@ -471,7 +439,7 @@ static int request_ping_pong(struct snd_pcm_substream *substream, prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f)); /* interrupt after every pong completion */ prtd->asp_params.opt |= TCINTEN | TCCHEN | - EDMA_TCC(prtd->ram_channel & 0x3f); + EDMA_TCC(EDMA_CHAN_SLOT(prtd->ram_channel)); edma_write_slot(link, &prtd->asp_params); /* ram */ @@ -559,13 +527,6 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - edma_start(prtd->asp_channel); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - prtd->ram_channel >= 0) { - /* copy 1st iram buffer */ - edma_start(prtd->ram_channel); - } - break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: edma_resume(prtd->asp_channel); @@ -589,7 +550,6 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream) { struct davinci_runtime_data *prtd = substream->runtime->private_data; - davinci_pcm_period_reset(substream); if (prtd->ram_channel >= 0) { int ret = ping_pong_dma_setup(substream); if (ret < 0) @@ -605,31 +565,21 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream) print_buf_info(prtd->asp_link[0], "asp_link[0]"); print_buf_info(prtd->asp_link[1], "asp_link[1]"); - /* - * There is a phase offset of 2 periods between the position - * used by dma setup and the position reported in the pointer - * function. - * - * The phase offset, when not using ping-pong buffers, is due to - * the two consecutive calls to davinci_pcm_enqueue_dma() below. - * - * Whereas here, with ping-pong buffers, the phase is due to - * there being an entire buffer transfer complete before the - * first dma completion event triggers davinci_pcm_dma_irq(). - */ - davinci_pcm_period_elapsed(substream); - davinci_pcm_period_elapsed(substream); - + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* copy 1st iram buffer */ + edma_start(prtd->ram_channel); + } + edma_start(prtd->asp_channel); return 0; } + prtd->period = 0; davinci_pcm_enqueue_dma(substream); - davinci_pcm_period_elapsed(substream); /* Copy self-linked parameter RAM entry into master channel */ edma_read_slot(prtd->asp_link[0], &prtd->asp_params); edma_write_slot(prtd->asp_channel, &prtd->asp_params); davinci_pcm_enqueue_dma(substream); - davinci_pcm_period_elapsed(substream); + edma_start(prtd->asp_channel); return 0; } @@ -641,23 +591,51 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream) struct davinci_runtime_data *prtd = runtime->private_data; unsigned int offset; int asp_count; - unsigned int period_size = snd_pcm_lib_period_bytes(substream); - - /* - * There is a phase offset of 2 periods between the position used by dma - * setup and the position reported in the pointer function. Either +2 in - * the dma setup or -2 here in the pointer function (with wrapping, - * both) accounts for this offset -- choose the latter since it makes - * the first-time setup clearer. - */ + dma_addr_t asp_src, asp_dst; + spin_lock(&prtd->lock); - asp_count = prtd->period - 2; + if (prtd->ram_channel >= 0) { + int ram_count; + int mod_ram; + dma_addr_t ram_src, ram_dst; + unsigned int period_size = snd_pcm_lib_period_bytes(substream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* reading ram before asp should be safe + * as long as the asp transfers less than a ping size + * of bytes between the 2 reads + */ + edma_get_position(prtd->ram_channel, + &ram_src, &ram_dst); + edma_get_position(prtd->asp_channel, + &asp_src, &asp_dst); + asp_count = asp_src - prtd->asp_params.src; + ram_count = ram_src - prtd->ram_params.src; + mod_ram = ram_count % period_size; + mod_ram -= asp_count; + if (mod_ram < 0) + mod_ram += period_size; + else if (mod_ram == 0) { + if (snd_pcm_running(substream)) + mod_ram += period_size; + } + ram_count -= mod_ram; + if (ram_count < 0) + ram_count += period_size * runtime->periods; + } else { + edma_get_position(prtd->ram_channel, + &ram_src, &ram_dst); + ram_count = ram_dst - prtd->ram_params.dst; + } + asp_count = ram_count; + } else { + edma_get_position(prtd->asp_channel, &asp_src, &asp_dst); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + asp_count = asp_src - runtime->dma_addr; + else + asp_count = asp_dst - runtime->dma_addr; + } spin_unlock(&prtd->lock); - if (asp_count < 0) - asp_count += runtime->periods; - asp_count *= period_size; - offset = bytes_to_frames(runtime, asp_count); if (offset >= runtime->buffer_size) offset = 0; @@ -833,11 +811,9 @@ static void davinci_pcm_free(struct snd_pcm *pcm) static u64 davinci_pcm_dmamask = 0xffffffff; -static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int davinci_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/ep93xx/ep93xx-pcm.c b/trunk/sound/soc/ep93xx/ep93xx-pcm.c index dd7ac5374cef..a07f99c9c375 100644 --- a/trunk/sound/soc/ep93xx/ep93xx-pcm.c +++ b/trunk/sound/soc/ep93xx/ep93xx-pcm.c @@ -283,11 +283,9 @@ static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 ep93xx_pcm_dmamask = 0xffffffff; -static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/fsl/fsl_dma.c b/trunk/sound/soc/fsl/fsl_dma.c index 732208c8c0b4..6680c0b4d203 100644 --- a/trunk/sound/soc/fsl/fsl_dma.c +++ b/trunk/sound/soc/fsl/fsl_dma.c @@ -294,11 +294,9 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) * Regardless of where the memory is actually allocated, since the device can * technically DMA to any 36-bit address, we do need to set the DMA mask to 36. */ -static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd) +static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; static u64 fsl_dma_dmamask = DMA_BIT_MASK(36); int ret; @@ -941,7 +939,7 @@ static int __devinit fsl_soc_dma_probe(struct platform_device *pdev) iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); if (iprop) - dma->ssi_fifo_depth = be32_to_cpup(iprop); + dma->ssi_fifo_depth = *iprop; else /* Older 8610 DTs didn't have the fifo-depth property */ dma->ssi_fifo_depth = 8; diff --git a/trunk/sound/soc/fsl/fsl_ssi.c b/trunk/sound/soc/fsl/fsl_ssi.c index d48afea5d93d..313e0ccedd5b 100644 --- a/trunk/sound/soc/fsl/fsl_ssi.c +++ b/trunk/sound/soc/fsl/fsl_ssi.c @@ -678,12 +678,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev) kfree(ssi_private); return ret; } - ssi_private->ssi = of_iomap(np, 0); - if (!ssi_private->ssi) { - dev_err(&pdev->dev, "could not map device resources\n"); - kfree(ssi_private); - return -ENOMEM; - } + ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start); ssi_private->ssi_phys = res.start; ssi_private->irq = irq_of_parse_and_map(np, 0); @@ -696,7 +691,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev) /* Determine the FIFO depth. */ iprop = of_get_property(np, "fsl,fifo-depth", NULL); if (iprop) - ssi_private->fifo_depth = be32_to_cpup(iprop); + ssi_private->fifo_depth = *iprop; else /* Older 8610 DTs didn't have the fifo-depth property */ ssi_private->fifo_depth = 8; diff --git a/trunk/sound/soc/fsl/mpc5200_dma.c b/trunk/sound/soc/fsl/mpc5200_dma.c index 19ad0c1be67e..fff695ccdd3e 100644 --- a/trunk/sound/soc/fsl/mpc5200_dma.c +++ b/trunk/sound/soc/fsl/mpc5200_dma.c @@ -299,11 +299,10 @@ static struct snd_pcm_ops psc_dma_ops = { }; static u64 psc_dma_dmamask = 0xffffffff; -static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) +static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; + struct snd_soc_pcm_runtime *rtd = pcm->private_data; struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); size_t size = psc_dma_hardware.buffer_bytes_max; int rc = 0; diff --git a/trunk/sound/soc/fsl/mpc8610_hpcd.c b/trunk/sound/soc/fsl/mpc8610_hpcd.c index a19297959587..c16c6b2eff95 100644 --- a/trunk/sound/soc/fsl/mpc8610_hpcd.c +++ b/trunk/sound/soc/fsl/mpc8610_hpcd.c @@ -233,7 +233,7 @@ static int get_parent_cell_index(struct device_node *np) if (!iprop) return -1; - return be32_to_cpup(iprop); + return *iprop; } /** @@ -258,7 +258,7 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) if (!iprop) return -EINVAL; - addr = be32_to_cpup(iprop); + addr = *iprop; bus = get_parent_cell_index(np); if (bus < 0) @@ -305,7 +305,7 @@ static int get_dma_channel(struct device_node *ssi_np, return -EINVAL; } - *dma_channel_id = be32_to_cpup(iprop); + *dma_channel_id = *iprop; *dma_id = get_parent_cell_index(dma_channel_np); of_node_put(dma_channel_np); @@ -379,7 +379,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) ret = -EINVAL; goto error; } - machine_data->ssi_id = be32_to_cpup(iprop); + machine_data->ssi_id = *iprop; /* Get the serial format and clock direction. */ sprop = of_get_property(np, "fsl,mode", NULL); @@ -405,7 +405,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) ret = -EINVAL; goto error; } - machine_data->clk_frequency = be32_to_cpup(iprop); + machine_data->clk_frequency = *iprop; } else if (strcasecmp(sprop, "i2s-master") == 0) { machine_data->dai_format = SND_SOC_DAIFMT_I2S; machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; diff --git a/trunk/sound/soc/fsl/p1022_ds.c b/trunk/sound/soc/fsl/p1022_ds.c index 8fa4d5f8eda1..66e0b68af147 100644 --- a/trunk/sound/soc/fsl/p1022_ds.c +++ b/trunk/sound/soc/fsl/p1022_ds.c @@ -232,7 +232,7 @@ static int get_parent_cell_index(struct device_node *np) iprop = of_get_property(parent, "cell-index", NULL); if (iprop) - ret = be32_to_cpup(iprop); + ret = *iprop; of_node_put(parent); @@ -261,7 +261,7 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) if (!iprop) return -EINVAL; - addr = be32_to_cpup(iprop); + addr = *iprop; bus = get_parent_cell_index(np); if (bus < 0) @@ -308,7 +308,7 @@ static int get_dma_channel(struct device_node *ssi_np, return -EINVAL; } - *dma_channel_id = be32_to_cpup(iprop); + *dma_channel_id = *iprop; *dma_id = get_parent_cell_index(dma_channel_np); of_node_put(dma_channel_np); @@ -379,7 +379,7 @@ static int p1022_ds_probe(struct platform_device *pdev) ret = -EINVAL; goto error; } - mdata->ssi_id = be32_to_cpup(iprop); + mdata->ssi_id = *iprop; /* Get the serial format and clock direction. */ sprop = of_get_property(np, "fsl,mode", NULL); @@ -405,7 +405,7 @@ static int p1022_ds_probe(struct platform_device *pdev) ret = -EINVAL; goto error; } - mdata->clk_frequency = be32_to_cpup(iprop); + mdata->clk_frequency = *iprop; } else if (strcasecmp(sprop, "i2s-master") == 0) { mdata->dai_format = SND_SOC_DAIFMT_I2S; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; diff --git a/trunk/sound/soc/imx/imx-pcm-fiq.c b/trunk/sound/soc/imx/imx-pcm-fiq.c index 309c59e6fb6c..413b78da248f 100644 --- a/trunk/sound/soc/imx/imx-pcm-fiq.c +++ b/trunk/sound/soc/imx/imx-pcm-fiq.c @@ -238,14 +238,12 @@ static struct snd_pcm_ops imx_pcm_ops = { static int ssi_irq = 0; -static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd) +static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret; - ret = imx_pcm_new(rtd); + ret = imx_pcm_new(card, dai, pcm); if (ret) return ret; diff --git a/trunk/sound/soc/imx/imx-ssi.c b/trunk/sound/soc/imx/imx-ssi.c index 10a8e2783751..61fceb09cdb5 100644 --- a/trunk/sound/soc/imx/imx-ssi.c +++ b/trunk/sound/soc/imx/imx-ssi.c @@ -388,11 +388,10 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) static u64 imx_pcm_dmamask = DMA_BIT_MASK(32); -int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) +int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; + int ret = 0; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/imx/imx-ssi.h b/trunk/sound/soc/imx/imx-ssi.h index 0a84cec3599e..dc8a87530e3e 100644 --- a/trunk/sound/soc/imx/imx-ssi.h +++ b/trunk/sound/soc/imx/imx-ssi.h @@ -225,7 +225,8 @@ struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev, struct imx_ssi *ssi); int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); -int imx_pcm_new(struct snd_soc_pcm_runtime *rtd); +int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm); void imx_pcm_free(struct snd_pcm *pcm); /* diff --git a/trunk/sound/soc/jz4740/jz4740-pcm.c b/trunk/sound/soc/jz4740/jz4740-pcm.c index a7c9578be983..fb1483f7c966 100644 --- a/trunk/sound/soc/jz4740/jz4740-pcm.c +++ b/trunk/sound/soc/jz4740/jz4740-pcm.c @@ -299,11 +299,9 @@ static void jz4740_pcm_free(struct snd_pcm *pcm) static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32); -int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd) +int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/kirkwood/kirkwood-dma.c b/trunk/sound/soc/kirkwood/kirkwood-dma.c index cd33de1c5b7a..e13c6ce46328 100644 --- a/trunk/sound/soc/kirkwood/kirkwood-dma.c +++ b/trunk/sound/soc/kirkwood/kirkwood-dma.c @@ -312,11 +312,9 @@ static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm, return 0; } -static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd) +static int kirkwood_dma_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/mid-x86/sst_platform.c b/trunk/sound/soc/mid-x86/sst_platform.c index 3e7826058efe..5a946b4115a2 100644 --- a/trunk/sound/soc/mid-x86/sst_platform.c +++ b/trunk/sound/soc/mid-x86/sst_platform.c @@ -402,10 +402,9 @@ static void sst_pcm_free(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } -int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) +int sst_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int retval = 0; pr_debug("sst_pcm_new called\n"); diff --git a/trunk/sound/soc/nuc900/nuc900-ac97.c b/trunk/sound/soc/nuc900/nuc900-ac97.c index 9c0edad90d8b..dac6732da969 100644 --- a/trunk/sound/soc/nuc900/nuc900-ac97.c +++ b/trunk/sound/soc/nuc900/nuc900-ac97.c @@ -356,7 +356,7 @@ static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev) nuc900_audio->irq_num = platform_get_irq(pdev, 0); if (!nuc900_audio->irq_num) { ret = -EBUSY; - goto out3; + goto out2; } nuc900_ac97_data = nuc900_audio; diff --git a/trunk/sound/soc/nuc900/nuc900-pcm.c b/trunk/sound/soc/nuc900/nuc900-pcm.c index d589ef14e917..8263f56dc665 100644 --- a/trunk/sound/soc/nuc900/nuc900-pcm.c +++ b/trunk/sound/soc/nuc900/nuc900-pcm.c @@ -315,12 +315,9 @@ static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm) } static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32); -static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd) +static int nuc900_dma_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; - if (!card->dev->dma_mask) card->dev->dma_mask = &nuc900_pcm_dmamask; if (!card->dev->coherent_dma_mask) diff --git a/trunk/sound/soc/omap/Kconfig b/trunk/sound/soc/omap/Kconfig index fe83d0d176be..99054cf1f68f 100644 --- a/trunk/sound/soc/omap/Kconfig +++ b/trunk/sound/soc/omap/Kconfig @@ -9,9 +9,6 @@ config SND_OMAP_SOC_MCBSP config SND_OMAP_SOC_MCPDM tristate -config SND_OMAP_SOC_HDMI - tristate - config SND_OMAP_SOC_N810 tristate "SoC Audio support for Nokia N810" depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C @@ -103,14 +100,6 @@ config SND_OMAP_SOC_SDP4430 Say Y if you want to add support for SoC audio on Texas Instruments SDP4430. -config SND_OMAP_SOC_OMAP4_HDMI - tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" - depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4 - select SND_OMAP_SOC_HDMI - help - Say Y if you want to add support for SoC HDMI audio on Texas Instruments - OMAP4 chips - config SND_OMAP_SOC_OMAP3_PANDORA tristate "SoC Audio support for OMAP3 Pandora" depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA diff --git a/trunk/sound/soc/omap/Makefile b/trunk/sound/soc/omap/Makefile index 59e2c8d1e38d..6c2c87eed5bb 100644 --- a/trunk/sound/soc/omap/Makefile +++ b/trunk/sound/soc/omap/Makefile @@ -2,12 +2,10 @@ snd-soc-omap-objs := omap-pcm.o snd-soc-omap-mcbsp-objs := omap-mcbsp.o snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o -snd-soc-omap-hdmi-objs := omap-hdmi.o obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o -obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o # OMAP Machine Support snd-soc-n810-objs := n810.o @@ -23,7 +21,6 @@ snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o snd-soc-zoom2-objs := zoom2.o snd-soc-igep0020-objs := igep0020.o -snd-soc-omap4-hdmi-objs := omap4-hdmi-card.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o @@ -39,4 +36,3 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o -obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o diff --git a/trunk/sound/soc/omap/ams-delta.c b/trunk/sound/soc/omap/ams-delta.c index b40095a19883..462cbcbea74a 100644 --- a/trunk/sound/soc/omap/ams-delta.c +++ b/trunk/sound/soc/omap/ams-delta.c @@ -427,8 +427,7 @@ static struct snd_soc_ops ams_delta_ops = { /* Board specific codec bias level control */ static int ams_delta_set_bias_level(struct snd_soc_card *card, - struct snd_soc_dapm_context *dapm, - enum snd_soc_bias_level level) + enum snd_soc_bias_level level) { struct snd_soc_codec *codec = card->rtd->codec; diff --git a/trunk/sound/soc/omap/omap-hdmi.c b/trunk/sound/soc/omap/omap-hdmi.c deleted file mode 100644 index 36c6eaeffb02..000000000000 --- a/trunk/sound/soc/omap/omap-hdmi.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * omap-hdmi.c - * - * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ - * Authors: Jorge Candelaria - * Ricardo Neri - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include "omap-pcm.h" -#include "omap-hdmi.h" - -#define DRV_NAME "hdmi-audio-dai" - -static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = { - .name = "HDMI playback", - .sync_mode = OMAP_DMA_SYNC_PACKET, -}; - -static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - int err; - /* - * Make sure that the period bytes are multiple of the DMA packet size. - * Largest packet size we use is 32 32-bit words = 128 bytes - */ - err = snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); - if (err < 0) - return err; - - return 0; -} - -static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - int err = 0; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - omap_hdmi_dai_dma_params.packet_size = 16; - break; - case SNDRV_PCM_FORMAT_S24_LE: - omap_hdmi_dai_dma_params.packet_size = 32; - break; - default: - err = -EINVAL; - } - - omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32; - - snd_soc_dai_set_dma_data(dai, substream, - &omap_hdmi_dai_dma_params); - - return err; -} - -static struct snd_soc_dai_ops omap_hdmi_dai_ops = { - .startup = omap_hdmi_dai_startup, - .hw_params = omap_hdmi_dai_hw_params, -}; - -static struct snd_soc_dai_driver omap_hdmi_dai = { - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = OMAP_HDMI_RATES, - .formats = OMAP_HDMI_FORMATS, - }, - .ops = &omap_hdmi_dai_ops, -}; - -static __devinit int omap_hdmi_probe(struct platform_device *pdev) -{ - int ret; - struct resource *hdmi_rsrc; - - hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!hdmi_rsrc) { - dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n"); - return -EINVAL; - } - - omap_hdmi_dai_dma_params.port_addr = hdmi_rsrc->start - + OMAP_HDMI_AUDIO_DMA_PORT; - - hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!hdmi_rsrc) { - dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n"); - return -EINVAL; - } - - omap_hdmi_dai_dma_params.dma_req = hdmi_rsrc->start; - - ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai); - return ret; -} - -static int __devexit omap_hdmi_remove(struct platform_device *pdev) -{ - snd_soc_unregister_dai(&pdev->dev); - return 0; -} - -static struct platform_driver hdmi_dai_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, - .probe = omap_hdmi_probe, - .remove = __devexit_p(omap_hdmi_remove), -}; - -static int __init hdmi_dai_init(void) -{ - return platform_driver_register(&hdmi_dai_driver); -} -module_init(hdmi_dai_init); - -static void __exit hdmi_dai_exit(void) -{ - platform_driver_unregister(&hdmi_dai_driver); -} -module_exit(hdmi_dai_exit); - -MODULE_AUTHOR("Jorge Candelaria "); -MODULE_AUTHOR("Ricardo Neri "); -MODULE_DESCRIPTION("OMAP HDMI SoC Interface"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/trunk/sound/soc/omap/omap-hdmi.h b/trunk/sound/soc/omap/omap-hdmi.h deleted file mode 100644 index 34c298d5057e..000000000000 --- a/trunk/sound/soc/omap/omap-hdmi.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * omap-hdmi.h - * - * Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ - * Authors: Jorge Candelaria - * Ricardo Neri - * - * 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 - * - */ - -#ifndef __OMAP_HDMI_H__ -#define __OMAP_HDMI_H__ - -#define OMAP_HDMI_AUDIO_DMA_PORT 0x8c - -#define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) - -#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S24_LE) - -#endif diff --git a/trunk/sound/soc/omap/omap-pcm.c b/trunk/sound/soc/omap/omap-pcm.c index b2f5751edae3..e6a6b991d05f 100644 --- a/trunk/sound/soc/omap/omap-pcm.c +++ b/trunk/sound/soc/omap/omap-pcm.c @@ -366,11 +366,9 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm) } } -static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) { - struct snd_card *card = rtd->card->snd_card; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) diff --git a/trunk/sound/soc/omap/omap4-hdmi-card.c b/trunk/sound/soc/omap/omap4-hdmi-card.c deleted file mode 100644 index 9f32615b81f7..000000000000 --- a/trunk/sound/soc/omap/omap4-hdmi-card.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * omap4-hdmi-card.c - * - * OMAP ALSA SoC machine driver for TI OMAP4 HDMI - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Ricardo Neri - * - * 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 -#include -#include -#include