diff options
33 files changed, 2452 insertions, 925 deletions
diff --git a/Documentation/devicetree/bindings/sound/ac97-bus.txt b/Documentation/devicetree/bindings/sound/ac97-bus.txt new file mode 100644 index 000000000000..103c428f2595 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ac97-bus.txt @@ -0,0 +1,32 @@ +Generic AC97 Device Properties + +This documents describes the devicetree bindings for an ac97 controller child +node describing ac97 codecs. + +Required properties: +-compatible : Must be "ac97,vendor_id1,vendor_id2 + The ids shall be the 4 characters hexadecimal encoding, such as + given by "%04x" formatting of printf +-reg : Must be the ac97 codec number, between 0 and 3 + +Example: +ac97: sound@40500000 { + compatible = "marvell,pxa270-ac97"; + reg = < 0x40500000 0x1000 >; + interrupts = <14>; + reset-gpios = <&gpio 95 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <1>; + pinctrl-names = "default"; + pinctrl-0 = < &pinctrl_ac97_default >; + clocks = <&clks CLK_AC97>, <&clks CLK_AC97CONF>; + clock-names = "AC97CLK", "AC97CONFCLK"; + + #address-cells = <1>; + #size-cells = <0>; + audio-codec@0 { + reg = <0>; + compatible = "ac97,574d,4c13"; + clocks = <&fixed_wm9713_clock>; + clock-names = "ac97_clk"; + } +}; diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst index 4d83c1c0ca04..4a3cecc8ad38 100644 --- a/Documentation/sound/alsa-configuration.rst +++ b/Documentation/sound/alsa-configuration.rst @@ -1568,7 +1568,7 @@ joystick_io The driver requires firmware files ``turtlebeach/msndinit.bin`` and ``turtlebeach/msndperm.bin`` in the proper firmware directory. -See Documentation/sound/oss/MultiSound for important information +See Documentation/sound/cards/multisound.sh for important information about this driver. Note that it has been discontinued, but the Voyetra Turtle Beach knowledge base entry for it is still available at diff --git a/Documentation/sound/cards/multisound.sh b/Documentation/sound/cards/multisound.sh new file mode 100755 index 000000000000..a915a1affcde --- /dev/null +++ b/Documentation/sound/cards/multisound.sh @@ -0,0 +1,1139 @@ +#! /bin/sh +# +# Turtle Beach MultiSound Driver Notes +# -- Andrew Veliath <andrewtv@usa.net> +# +# Last update: September 10, 1998 +# Corresponding msnd driver: 0.8.3 +# +# ** This file is a README (top part) and shell archive (bottom part). +# The corresponding archived utility sources can be unpacked by +# running `sh MultiSound' (the utilities are only needed for the +# Pinnacle and Fiji cards). ** +# +# +# -=-=- Getting Firmware -=-=- +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# See the section `Obtaining and Creating Firmware Files' in this +# document for instructions on obtaining the necessary firmware +# files. +# +# +# Supported Features +# ~~~~~~~~~~~~~~~~~~ +# +# Currently, full-duplex digital audio (/dev/dsp only, /dev/audio is +# not currently available) and mixer functionality (/dev/mixer) are +# supported (memory mapped digital audio is not yet supported). +# Digital transfers and monitoring can be done as well if you have +# the digital daughterboard (see the section on using the S/PDIF port +# for more information). +# +# Support for the Turtle Beach MultiSound Hurricane architecture is +# composed of the following modules (these can also operate compiled +# into the kernel): +# +# snd-msnd-lib - MultiSound base (requires snd) +# +# snd-msnd-classic - Base audio/mixer support for Classic, Monetery and +# Tahiti cards +# +# snd-msnd-pinnacle - Base audio/mixer support for Pinnacle and Fiji cards +# +# +# Important Notes - Read Before Using +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# The firmware files are not included (may change in future). You +# must obtain these images from Turtle Beach (they are included in +# the MultiSound Development Kits), and place them in /etc/sound for +# example, and give the full paths in the Linux configuration. If +# you are compiling in support for the MultiSound driver rather than +# using it as a module, these firmware files must be accessible +# during kernel compilation. +# +# Please note these files must be binary files, not assembler. See +# the section later in this document for instructions to obtain these +# files. +# +# +# Configuring Card Resources +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# ** This section is very important, as your card may not work at all +# or your machine may crash if you do not do this correctly. ** +# +# * Classic/Monterey/Tahiti +# +# These cards are configured through the driver snd-msnd-classic. You must +# know the io port, then the driver will select the irq and memory resources +# on the card. It is up to you to know if these are free locations or now, +# a conflict can lock the machine up. +# +# * Pinnacle/Fiji +# +# The Pinnacle and Fiji cards have an extra config port, either +# 0x250, 0x260 or 0x270. This port can be disabled to have the card +# configured strictly through PnP, however you lose the ability to +# access the IDE controller and joystick devices on this card when +# using PnP. The included pinnaclecfg program in this shell archive +# can be used to configure the card in non-PnP mode, and in PnP mode +# you can use isapnptools. These are described briefly here. +# +# pinnaclecfg is not required; you can use the snd-msnd-pinnacle module +# to fully configure the card as well. However, pinnaclecfg can be +# used to change the resource values of a particular device after the +# snd-msnd-pinnacle module has been loaded. If you are compiling the +# driver into the kernel, you must set these values during compile +# time, however other peripheral resource values can be changed with +# the pinnaclecfg program after the kernel is loaded. +# +# +# *** PnP mode +# +# Use pnpdump to obtain a sample configuration if you can; I was able +# to obtain one with the command `pnpdump 1 0x203' -- this may vary +# for you (running pnpdump by itself did not work for me). Then, +# edit this file and use isapnp to uncomment and set the card values. +# Use these values when inserting the snd-msnd-pinnacle module. Using +# this method, you can set the resources for the DSP and the Kurzweil +# synth (Pinnacle). Since Linux does not directly support PnP +# devices, you may have difficulty when using the card in PnP mode +# when it the driver is compiled into the kernel. Using non-PnP mode +# is preferable in this case. +# +# Here is an example mypinnacle.conf for isapnp that sets the card to +# io base 0x210, irq 5 and mem 0xd8000, and also sets the Kurzweil +# synth to 0x330 and irq 9 (may need editing for your system): +# +# (READPORT 0x0203) +# (CSN 2) +# (IDENTIFY *) +# +# # DSP +# (CONFIGURE BVJ0440/-1 (LD 0 +# (INT 0 (IRQ 5 (MODE +E))) (IO 0 (BASE 0x0210)) (MEM 0 (BASE 0x0d8000)) +# (ACT Y))) +# +# # Kurzweil Synth (Pinnacle Only) +# (CONFIGURE BVJ0440/-1 (LD 1 +# (IO 0 (BASE 0x0330)) (INT 0 (IRQ 9 (MODE +E))) +# (ACT Y))) +# +# (WAITFORKEY) +# +# +# *** Non-PnP mode +# +# The second way is by running the card in non-PnP mode. This +# actually has some advantages in that you can access some other +# devices on the card, such as the joystick and IDE controller. To +# configure the card, unpack this shell archive and build the +# pinnaclecfg program. Using this program, you can assign the +# resource values to the card's devices, or disable the devices. As +# an alternative to using pinnaclecfg, you can specify many of the +# configuration values when loading the snd-msnd-pinnacle module (or +# during kernel configuration when compiling the driver into the +# kernel). +# +# If you specify cfg=0x250 for the snd-msnd-pinnacle module, it +# automatically configure the card to the given io, irq and memory +# values using that config port (the config port is jumper selectable +# on the card to 0x250, 0x260 or 0x270). +# +# See the `snd-msnd-pinnacle Additional Options' section below for more +# information on these parameters (also, if you compile the driver +# directly into the kernel, these extra parameters can be useful +# here). +# +# +# ** It is very easy to cause problems in your machine if you choose a +# resource value which is incorrect. ** +# +# +# Examples +# ~~~~~~~~ +# +# * MultiSound Classic/Monterey/Tahiti: +# +# modprobe snd +# insmod snd-msnd-lib +# insmod snd-msnd-classic io=0x290 irq=7 mem=0xd0000 +# +# * MultiSound Pinnacle in PnP mode: +# +# modprobe snd +# insmod snd-msnd-lib +# isapnp mypinnacle.conf +# insmod snd-msnd-pinnacle io=0x210 irq=5 mem=0xd8000 <-- match mypinnacle.conf values +# +# * MultiSound Pinnacle in non-PnP mode (replace 0x250 with your configuration port, +# one of 0x250, 0x260 or 0x270): +# +# modprobe snd +# insmod snd-msnd-lib +# insmod snd-msnd-pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 +# +# * To use the MPU-compatible Kurzweil synth on the Pinnacle in PnP +# mode, add the following (assumes you did `isapnp mypinnacle.conf'): +# +# insmod snd +# insmod mpu401 io=0x330 irq=9 <-- match mypinnacle.conf values +# +# * To use the MPU-compatible Kurzweil synth on the Pinnacle in non-PnP +# mode, add the following. Note how we first configure the peripheral's +# resources, _then_ install a Linux driver for it: +# +# insmod snd +# pinnaclecfg 0x250 mpu 0x330 9 +# insmod mpu401 io=0x330 irq=9 +# +# -- OR you can use the following sequence without pinnaclecfg in non-PnP mode: +# +# modprobe snd +# insmod snd-msnd-lib +# insmod snd-msnd-pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 mpu_io=0x330 mpu_irq=9 +# insmod snd +# insmod mpu401 io=0x330 irq=9 +# +# * To setup the joystick port on the Pinnacle in non-PnP mode (though +# you have to find the actual Linux joystick driver elsewhere), you +# can use pinnaclecfg: +# +# pinnaclecfg 0x250 joystick 0x200 +# +# -- OR you can configure this using snd-msnd-pinnacle with the following: +# +# modprobe snd +# insmod snd-msnd-lib +# insmod snd-msnd-pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 joystick_io=0x200 +# +# +# snd-msnd-classic, snd-msnd-pinnacle Required Options +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# If the following options are not given, the module will not load. +# Examine the kernel message log for informative error messages. +# WARNING--probing isn't supported so try to make sure you have the +# correct shared memory area, otherwise you may experience problems. +# +# io I/O base of DSP, e.g. io=0x210 +# irq IRQ number, e.g. irq=5 +# mem Shared memory area, e.g. mem=0xd8000 +# +# +# snd-msnd-classic, snd-msnd-pinnacle Additional Options +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# fifosize The digital audio FIFOs, in kilobytes. If not +# specified, the default will be used. Increasing +# this value will reduce the chance of a FIFO +# underflow at the expense of increasing overall +# latency. For example, fifosize=512 will +# allocate 512kB read and write FIFOs (1MB total). +# While this may reduce dropouts, a heavy machine +# load will undoubtedly starve the FIFO of data +# and you will eventually get dropouts. One +# option is to alter the scheduling priority of +# the playback process, using `nice' or some form +# of POSIX soft real-time scheduling. +# +# calibrate_signal Setting this to one calibrates the ADCs to the +# signal, zero calibrates to the card (defaults +# to zero). +# +# +# snd-msnd-pinnacle Additional Options +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# digital Specify digital=1 to enable the S/PDIF input +# if you have the digital daughterboard +# adapter. This will enable access to the +# DIGITAL1 input for the soundcard in the mixer. +# Some mixer programs might have trouble setting +# the DIGITAL1 source as an input. If you have +# trouble, you can try the setdigital.c program +# at the bottom of this document. +# +# cfg Non-PnP configuration port for the Pinnacle +# and Fiji (typically 0x250, 0x260 or 0x270, +# depending on the jumper configuration). If +# this option is omitted, then it is assumed +# that the card is in PnP mode, and that the +# specified DSP resource values are already +# configured with PnP (i.e. it won't attempt to +# do any sort of configuration). +# +# When the Pinnacle is in non-PnP mode, you can use the following +# options to configure particular devices. If a full specification +# for a device is not given, then the device is not configured. Note +# that you still must use a Linux driver for any of these devices +# once their resources are setup (such as the Linux joystick driver, +# or the MPU401 driver from OSS for the Kurzweil synth). +# +# mpu_io I/O port of MPU (on-board Kurzweil synth) +# mpu_irq IRQ of MPU (on-board Kurzweil synth) +# ide_io0 First I/O port of IDE controller +# ide_io1 Second I/O port of IDE controller +# ide_irq IRQ IDE controller +# joystick_io I/O port of joystick +# +# +# Obtaining and Creating Firmware Files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# For the Classic/Tahiti/Monterey +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Download to /tmp and unzip the following file from Turtle Beach: +# +# ftp://ftp.voyetra.com/pub/tbs/msndcl/msndvkit.zip +# +# When unzipped, unzip the file named MsndFiles.zip. Then copy the +# following firmware files to /etc/sound (note the file renaming): +# +# cp DSPCODE/MSNDINIT.BIN /etc/sound/msndinit.bin +# cp DSPCODE/MSNDPERM.REB /etc/sound/msndperm.bin +# +# When configuring the Linux kernel, specify /etc/sound/msndinit.bin and +# /etc/sound/msndperm.bin for the two firmware files (Linux kernel +# versions older than 2.2 do not ask for firmware paths, and are +# hardcoded to /etc/sound). +# +# If you are compiling the driver into the kernel, these files must +# be accessible during compilation, but will not be needed later. +# The files must remain, however, if the driver is used as a module. +# +# +# For the Pinnacle/Fiji +# ~~~~~~~~~~~~~~~~~~~~~ +# +# Download to /tmp and unzip the following file from Turtle Beach (be +# sure to use the entire URL; some have had trouble navigating to the +# URL): +# +# ftp://ftp.voyetra.com/pub/tbs/pinn/pnddk100.zip +# +# Unpack this shell archive, and run make in the created directory +# (you need a C compiler and flex to build the utilities). This +# should give you the executables conv, pinnaclecfg and setdigital. +# conv is only used temporarily here to create the firmware files, +# while pinnaclecfg is used to configure the Pinnacle or Fiji card in +# non-PnP mode, and setdigital can be used to set the S/PDIF input on +# the mixer (pinnaclecfg and setdigital should be copied to a +# convenient place, possibly run during system initialization). +# +# To generating the firmware files with the `conv' program, we create +# the binary firmware files by doing the following conversion +# (assuming the archive unpacked into a directory named PINNDDK): +# +# ./conv < PINNDDK/dspcode/pndspini.asm > /etc/sound/pndspini.bin +# ./conv < PINNDDK/dspcode/pndsperm.asm > /etc/sound/pndsperm.bin +# +# The conv (and conv.l) program is not needed after conversion and can +# be safely deleted. Then, when configuring the Linux kernel, specify +# /etc/sound/pndspini.bin and /etc/sound/pndsperm.bin for the two +# firmware files (Linux kernel versions older than 2.2 do not ask for +# firmware paths, and are hardcoded to /etc/sound). +# +# If you are compiling the driver into the kernel, these files must +# be accessible during compilation, but will not be needed later. +# The files must remain, however, if the driver is used as a module. +# +# +# Using Digital I/O with the S/PDIF Port +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# If you have a Pinnacle or Fiji with the digital daughterboard and +# want to set it as the input source, you can use this program if you +# have trouble trying to do it with a mixer program (be sure to +# insert the module with the digital=1 option, or say Y to the option +# during compiled-in kernel operation). Upon selection of the S/PDIF +# port, you should be able monitor and record from it. +# +# There is something to note about using the S/PDIF port. Digital +# timing is taken from the digital signal, so if a signal is not +# connected to the port and it is selected as recording input, you +# will find PCM playback to be distorted in playback rate. Also, +# attempting to record at a sampling rate other than the DAT rate may +# be problematic (i.e. trying to record at 8000Hz when the DAT signal +# is 44100Hz). If you have a problem with this, set the recording +# input to analog if you need to record at a rate other than that of +# the DAT rate. +# +# +# -- Shell archive attached below, just run `sh MultiSound' to extract. +# Contains Pinnacle/Fiji utilities to convert firmware, configure +# in non-PnP mode, and select the DIGITAL1 input for the mixer. +# +# +#!/bin/sh +# This is a shell archive (produced by GNU sharutils 4.2). +# To extract the files from this archive, save it to some FILE, remove +# everything before the `!/bin/sh' line above, then type `sh FILE'. +# +# Made on 1998-12-04 10:07 EST by <andrewtv@ztransform.velsoft.com>. +# Source directory was `/home/andrewtv/programming/pinnacle/pinnacle'. +# +# Existing files will *not* be overwritten unless `-c' is specified. +# +# This shar contains: +# length mode name +# ------ ---------- ------------------------------------------ +# 2064 -rw-rw-r-- MultiSound.d/setdigital.c +# 10224 -rw-rw-r-- MultiSound.d/pinnaclecfg.c +# 106 -rw-rw-r-- MultiSound.d/Makefile +# 146 -rw-rw-r-- MultiSound.d/conv.l +# 1491 -rw-rw-r-- MultiSound.d/msndreset.c +# +save_IFS="${IFS}" +IFS="${IFS}:" +gettext_dir=FAILED +locale_dir=FAILED +first_param="$1" +for dir in $PATH +do + if test "$gettext_dir" = FAILED && test -f $dir/gettext \ + && ($dir/gettext --version >/dev/null 2>&1) + then + set `$dir/gettext --version 2>&1` + if test "$3" = GNU + then + gettext_dir=$dir + fi + fi + if test "$locale_dir" = FAILED && test -f $dir/shar \ + && ($dir/shar --print-text-domain-dir >/dev/null 2>&1) + then + locale_dir=`$dir/shar --print-text-domain-dir` + fi +done +IFS="$save_IFS" +if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED +then + echo=echo +else + TEXTDOMAINDIR=$locale_dir + export TEXTDOMAINDIR + TEXTDOMAIN=sharutils + export TEXTDOMAIN + echo="$gettext_dir/gettext -s" +fi +touch -am 1231235999 $$.touch >/dev/null 2>&1 +if test ! -f 1231235999 && test -f $$.touch; then + shar_touch=touch +else + shar_touch=: + echo + $echo 'WARNING: not restoring timestamps. Consider getting and' + $echo "installing GNU \`touch', distributed in GNU File Utilities..." + echo +fi +rm -f 1231235999 $$.touch +# +if mkdir _sh01426; then + $echo 'x -' 'creating lock directory' +else + $echo 'failed to create lock directory' + exit 1 +fi +# ============= MultiSound.d/setdigital.c ============== +if test ! -d 'MultiSound.d'; then + $echo 'x -' 'creating directory' 'MultiSound.d' + mkdir 'MultiSound.d' +fi +if test -f 'MultiSound.d/setdigital.c' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'MultiSound.d/setdigital.c' '(file already exists)' +else + $echo 'x -' extracting 'MultiSound.d/setdigital.c' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/setdigital.c' && +/********************************************************************* +X * +X * setdigital.c - sets the DIGITAL1 input for a mixer +X * +X * Copyright (C) 1998 Andrew Veliath +X * +X * This program is free software; you can redistribute it and/or modify +X * it under the terms of the GNU General Public License as published by +X * the Free Software Foundation; either version 2 of the License, or +X * (at your option) any later version. +X * +X * This program is distributed in the hope that it will be useful, +X * but WITHOUT ANY WARRANTY; without even the implied warranty of +X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +X * GNU General Public License for more details. +X * +X * You should have received a copy of the GNU General Public License +X * along with this program; if not, write to the Free Software +X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +X * +X ********************************************************************/ +X +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/soundcard.h> +X +int main(int argc, char *argv[]) +{ +X int fd; +X unsigned long recmask, recsrc; +X +X if (argc != 2) { +X fprintf(stderr, "usage: setdigital <mixer device>\n"); +X exit(1); +X } +X +X if ((fd = open(argv[1], O_RDWR)) < 0) { +X perror(argv[1]); +X exit(1); +X } +X +X if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) < 0) { +X fprintf(stderr, "error: ioctl read recording mask failed\n"); +X perror("ioctl"); +X close(fd); +X exit(1); +X } +X +X if (!(recmask & SOUND_MASK_DIGITAL1)) { +X fprintf(stderr, "error: cannot find DIGITAL1 device in mixer\n"); +X close(fd); +X exit(1); +X } +X +X if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) < 0) { +X fprintf(stderr, "error: ioctl read recording source failed\n"); +X perror("ioctl"); +X close(fd); +X exit(1); +X } +X +X recsrc |= SOUND_MASK_DIGITAL1; +X +X if (ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) < 0) { +X fprintf(stderr, "error: ioctl write recording source failed\n"); +X perror("ioctl"); +X close(fd); +X exit(1); +X } +X +X close(fd); +X +X return 0; +} +SHAR_EOF + $shar_touch -am 1204092598 'MultiSound.d/setdigital.c' && + chmod 0664 'MultiSound.d/setdigital.c' || + $echo 'restore of' 'MultiSound.d/setdigital.c' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'MultiSound.d/setdigital.c:' 'MD5 check failed' +e87217fc3e71288102ba41fd81f71ec4 MultiSound.d/setdigital.c +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/setdigital.c'`" + test 2064 -eq "$shar_count" || + $echo 'MultiSound.d/setdigital.c:' 'original size' '2064,' 'current size' "$shar_count!" + fi +fi +# ============= MultiSound.d/pinnaclecfg.c ============== +if test -f 'MultiSound.d/pinnaclecfg.c' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'MultiSound.d/pinnaclecfg.c' '(file already exists)' +else + $echo 'x -' extracting 'MultiSound.d/pinnaclecfg.c' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/pinnaclecfg.c' && +/********************************************************************* +X * +X * pinnaclecfg.c - Pinnacle/Fiji Device Configuration Program +X * +X * This is for NON-PnP mode only. For PnP mode, use isapnptools. +X * +X * This is Linux-specific, and must be run with root permissions. +X * +X * Part of the Turtle Beach MultiSound Sound Card Driver for Linux +X * +X * Copyright (C) 1998 Andrew Veliath +X * +X * This program is free software; you can redistribute it and/or modify +X * it under the terms of the GNU General Public License as published by +X * the Free Software Foundation; either version 2 of the License, or +X * (at your option) any later version. +X * +X * This program is distributed in the hope that it will be useful, +X * but WITHOUT ANY WARRANTY; without even the implied warranty of +X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +X * GNU General Public License for more details. +X * +X * You should have received a copy of the GNU General Public License +X * along with this program; if not, write to the Free Software +X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +X * +X ********************************************************************/ +X +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <asm/types.h> +#include <sys/io.h> +X +#define IREG_LOGDEVICE 0x07 +#define IREG_ACTIVATE 0x30 +#define LD_ACTIVATE 0x01 +#define LD_DISACTIVATE 0x00 +#define IREG_EECONTROL 0x3F +#define IREG_MEMBASEHI 0x40 +#define IREG_MEMBASELO 0x41 +#define IREG_MEMCONTROL 0x42 +#define IREG_MEMRANGEHI 0x43 +#define IREG_MEMRANGELO 0x44 +#define MEMTYPE_8BIT 0x00 +#define MEMTYPE_16BIT 0x02 +#define MEMTYPE_RANGE 0x00 +#define MEMTYPE_HIADDR 0x01 +#define IREG_IO0_BASEHI 0x60 +#define IREG_IO0_BASELO 0x61 +#define IREG_IO1_BASEHI 0x62 +#define IREG_IO1_BASELO 0x63 +#define IREG_IRQ_NUMBER 0x70 +#define IREG_IRQ_TYPE 0x71 +#define IRQTYPE_HIGH 0x02 +#define IRQTYPE_LOW 0x00 +#define IRQTYPE_LEVEL 0x01 +#define IRQTYPE_EDGE 0x00 +X +#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF)) +#define LOBYTE(w) ((BYTE)(w)) +#define MAKEWORD(low,hi) ((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8))) +X +typedef __u8 BYTE; +typedef __u16 USHORT; +typedef __u16 WORD; +X +static int config_port = -1; +X +static int msnd_write_cfg(int cfg, int reg, int value) +{ +X outb(reg, cfg); +X outb(value, cfg + 1); +X if (value != inb(cfg + 1)) { +X fprintf(stderr, "error: msnd_write_cfg: I/O error\n"); +X return -EIO; +X } +X return 0; +} +X +static int msnd_read_cfg(int cfg, int reg) +{ +X outb(reg, cfg); +X return inb(cfg + 1); +} +X +static int msnd_write_cfg_io0(int cfg, int num, WORD io) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io))) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io))) +X return -EIO; +X return 0; +} +X +static int msnd_read_cfg_io0(int cfg, int num, WORD *io) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X +X *io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO0_BASELO), +X msnd_read_cfg(cfg, IREG_IO0_BASEHI)); +X +X return 0; +} +X +static int msnd_write_cfg_io1(int cfg, int num, WORD io) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io))) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io))) +X return -EIO; +X return 0; +} +X +static int msnd_read_cfg_io1(int cfg, int num, WORD *io) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X +X *io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO1_BASELO), +X msnd_read_cfg(cfg, IREG_IO1_BASEHI)); +X +X return 0; +} +X +static int msnd_write_cfg_irq(int cfg, int num, WORD irq) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq))) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE)) +X return -EIO; +X return 0; +} +X +static int msnd_read_cfg_irq(int cfg, int num, WORD *irq) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X +X *irq = msnd_read_cfg(cfg, IREG_IRQ_NUMBER); +X +X return 0; +} +X +static int msnd_write_cfg_mem(int cfg, int num, int mem) +{ +X WORD wmem; +X +X mem >>= 8; +X mem &= 0xfff; +X wmem = (WORD)mem; +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem))) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem))) +X return -EIO; +X if (wmem && msnd_write_cfg(cfg, IREG_MEMCONTROL, (MEMTYPE_HIADDR | MEMTYPE_16BIT))) +X return -EIO; +X return 0; +} +X +static int msnd_read_cfg_mem(int cfg, int num, int *mem) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X +X *mem = MAKEWORD(msnd_read_cfg(cfg, IREG_MEMBASELO), +X msnd_read_cfg(cfg, IREG_MEMBASEHI)); +X *mem <<= 8; +X +X return 0; +} +X +static int msnd_activate_logical(int cfg, int num) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE)) +X return -EIO; +X return 0; +} +X +static int msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg_io0(cfg, num, io0)) +X return -EIO; +X if (msnd_write_cfg_io1(cfg, num, io1)) +X return -EIO; +X if (msnd_write_cfg_irq(cfg, num, irq)) +X return -EIO; +X if (msnd_write_cfg_mem(cfg, num, mem)) +X return -EIO; +X if (msnd_activate_logical(cfg, num)) +X return -EIO; +X return 0; +} +X +static int msnd_read_cfg_logical(int cfg, int num, WORD *io0, WORD *io1, WORD *irq, int *mem) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_read_cfg_io0(cfg, num, io0)) +X return -EIO; +X if (msnd_read_cfg_io1(cfg, num, io1)) +X return -EIO; +X if (msnd_read_cfg_irq(cfg, num, irq)) +X return -EIO; +X if (msnd_read_cfg_mem(cfg, num, mem)) +X return -EIO; +X return 0; +} +X +static void usage(void) +{ +X fprintf(stderr, +X "\n" +X "pinnaclecfg 1.0\n" +X "\n" +X "usage: pinnaclecfg <config port> [device config]\n" +X "\n" +X "This is for use with the card in NON-PnP mode only.\n" +X "\n" +X "Available devices (not all available for Fiji):\n" +X "\n" +X " Device Description\n" +X " -------------------------------------------------------------------\n" +X " reset Reset all devices (i.e. disable)\n" +X " show Display current device configurations\n" +X "\n" +X " dsp <io> <irq> <mem> Audio device\n" +X " mpu <io> <irq> Internal Kurzweil synth\n" +X " ide <io0> <io1> <irq> On-board IDE controller\n" +X " joystick <io> Joystick port\n" +X "\n"); +X exit(1); +} +X +static int cfg_reset(void) +{ +X int i; +X +X for (i = 0; i < 4; ++i) +X msnd_write_cfg_logical(config_port, i, 0, 0, 0, 0); +X +X return 0; +} +X +static int cfg_show(void) +{ +X int i; +X int count = 0; +X +X for (i = 0; i < 4; ++i) { +X WORD io0, io1, irq; +X int mem; +X msnd_read_cfg_logical(config_port, i, &io0, &io1, &irq, &mem); +X switch (i) { +X case 0: +X if (io0 || irq || mem) { +X printf("dsp 0x%x %d 0x%x\n", io0, irq, mem); +X ++count; +X } +X break; +X case 1: +X if (io0 || irq) { +X printf("mpu 0x%x %d\n", io0, irq); +X ++count; +X } +X break; +X case 2: +X if (io0 || io1 || irq) { +X printf("ide 0x%x 0x%x %d\n", io0, io1, irq); +X ++count; +X } +X break; +X case 3: +X if (io0) { +X printf("joystick 0x%x\n", io0); +X ++count; +X } +X break; +X } +X } +X +X if (count == 0) +X fprintf(stderr, "no devices configured\n"); +X +X return 0; +} +X +static int cfg_dsp(int argc, char *argv[]) +{ +X int io, irq, mem; +X +X if (argc < 3 || +X sscanf(argv[0], "0x%x", &io) != 1 || +X sscanf(argv[1], "%d", &irq) != 1 || +X sscanf(argv[2], "0x%x", &mem) != 1) +X usage(); +X +X if (!(io == 0x290 || +X io == 0x260 || +X io == 0x250 || +X io == 0x240 || +X io == 0x230 || +X io == 0x220 || +X io == 0x210 || +X io == 0x3e0)) { +X fprintf(stderr, "error: io must be one of " +X "210, 220, 230, 240, 250, 260, 290, or 3E0\n"); +X usage(); +X } +X +X if (!(irq == 5 || +X irq == 7 || +X irq == 9 || +X irq == 10 || +X irq == 11 || +X irq == 12)) { +X fprintf(stderr, "error: irq must be one of " +X "5, 7, 9, 10, 11 or 12\n"); +X usage(); +X } +X +X if (!(mem == 0xb0000 || +X mem == 0xc8000 || +X mem == 0xd0000 || +X mem == 0xd8000 || +X mem == 0xe0000 || +X mem == 0xe8000)) { +X fprintf(stderr, "error: mem must be one of " +X "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n"); +X usage(); +X } +X +X return msnd_write_cfg_logical(config_port, 0, io, 0, irq, mem); +} +X +static int cfg_mpu(int argc, char *argv[]) +{ +X int io, irq; +X +X if (argc < 2 || +X sscanf(argv[0], "0x%x", &io) != 1 || +X sscanf(argv[1], "%d", &irq) != 1) +X usage(); +X +X return msnd_write_cfg_logical(config_port, 1, io, 0, irq, 0); +} +X +static int cfg_ide(int argc, char *argv[]) +{ +X int io0, io1, irq; +X +X if (argc < 3 || +X sscanf(argv[0], "0x%x", &io0) != 1 || +X sscanf(argv[0], "0x%x", &io1) != 1 || +X sscanf(argv[1], "%d", &irq) != 1) +X usage(); +X +X return msnd_write_cfg_logical(config_port, 2, io0, io1, irq, 0); +} +X +static int cfg_joystick(int argc, char *argv[]) +{ +X int io; +X +X if (argc < 1 || +X sscanf(argv[0], "0x%x", &io) != 1) +X usage(); +X +X return msnd_write_cfg_logical(config_port, 3, io, 0, 0, 0); +} +X +int main(int argc, char *argv[]) +{ +X char *device; +X int rv = 0; +X +X --argc; ++argv; +X +X if (argc < 2) +X usage(); +X +X sscanf(argv[0], "0x%x", &config_port); +X if (config_port != 0x250 && config_port != 0x260 && config_port != 0x270) { +X fprintf(stderr, "error: <config port> must be 0x250, 0x260 or 0x270\n"); +X exit(1); +X } +X if (ioperm(config_port, 2, 1)) { +X perror("ioperm"); +X fprintf(stderr, "note: pinnaclecfg must be run as root\n"); +X exit(1); +X } +X device = argv[1]; +X +X argc -= 2; argv += 2; +X +X if (strcmp(device, "reset") == 0) +X rv = cfg_reset(); +X else if (strcmp(device, "show") == 0) +X rv = cfg_show(); +X else if (strcmp(device, "dsp") == 0) +X rv = cfg_dsp(argc, argv); +X else if (strcmp(device, "mpu") == 0) +X rv = cfg_mpu(argc, argv); +X else if (strcmp(device, "ide") == 0) +X rv = cfg_ide(argc, argv); +X else if (strcmp(device, "joystick") == 0) +X rv = cfg_joystick(argc, argv); +X else { +X fprintf(stderr, "error: unknown device %s\n", device); +X usage(); +X } +X +X if (rv) +X fprintf(stderr, "error: device configuration failed\n"); +X +X return 0; +} +SHAR_EOF + $shar_touch -am 1204092598 'MultiSound.d/pinnaclecfg.c' && + chmod 0664 'MultiSound.d/pinnaclecfg.c' || + $echo 'restore of' 'MultiSound.d/pinnaclecfg.c' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'MultiSound.d/pinnaclecfg.c:' 'MD5 check failed' +366bdf27f0db767a3c7921d0a6db20fe MultiSound.d/pinnaclecfg.c +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/pinnaclecfg.c'`" + test 10224 -eq "$shar_count" || + $echo 'MultiSound.d/pinnaclecfg.c:' 'original size' '10224,' 'current size' "$shar_count!" + fi +fi +# ============= MultiSound.d/Makefile ============== +if test -f 'MultiSound.d/Makefile' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'MultiSound.d/Makefile' '(file already exists)' +else + $echo 'x -' extracting 'MultiSound.d/Makefile' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/Makefile' && +CC = gcc +CFLAGS = -O +PROGS = setdigital msndreset pinnaclecfg conv +X +all: $(PROGS) +X +clean: +X rm -f $(PROGS) +SHAR_EOF + $shar_touch -am 1204092398 'MultiSound.d/Makefile' && + chmod 0664 'MultiSound.d/Makefile' || + $echo 'restore of' 'MultiSound.d/Makefile' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'MultiSound.d/Makefile:' 'MD5 check failed' +76ca8bb44e3882edcf79c97df6c81845 MultiSound.d/Makefile +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/Makefile'`" + test 106 -eq "$shar_count" || + $echo 'MultiSound.d/Makefile:' 'original size' '106,' 'current size' "$shar_count!" + fi +fi +# ============= MultiSound.d/conv.l ============== +if test -f 'MultiSound.d/conv.l' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'MultiSound.d/conv.l' '(file already exists)' +else + $echo 'x -' extracting 'MultiSound.d/conv.l' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/conv.l' && +%% +[ \n\t,\r] +\;.* +DB +[0-9A-Fa-f]+H { int n; sscanf(yytext, "%xH", &n); printf("%c", n); } +%% +int yywrap() { return 1; } +void main() { yylex(); } +SHAR_EOF + $shar_touch -am 0828231798 'MultiSound.d/conv.l' && + chmod 0664 'MultiSound.d/conv.l' || + $echo 'restore of' 'MultiSound.d/conv.l' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'MultiSound.d/conv.l:' 'MD5 check failed' +d2411fc32cd71a00dcdc1f009e858dd2 MultiSound.d/conv.l +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/conv.l'`" + test 146 -eq "$shar_count" || + $echo 'MultiSound.d/conv.l:' 'original size' '146,' 'current size' "$shar_count!" + fi +fi +# ============= MultiSound.d/msndreset.c ============== +if test -f 'MultiSound.d/msndreset.c' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'MultiSound.d/msndreset.c' '(file already exists)' +else + $echo 'x -' extracting 'MultiSound.d/msndreset.c' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/msndreset.c' && +/********************************************************************* +X * +X * msndreset.c - resets the MultiSound card +X * +X * Copyright (C) 1998 Andrew Veliath +X * +X * This program is free software; you can redistribute it and/or modify +X * it under the terms of the GNU General Public License as published by +X * the Free Software Foundation; either version 2 of the License, or +X * (at your option) any later version. +X * +X * This program is distributed in the hope that it will be useful, +X * but WITHOUT ANY WARRANTY; without even the implied warranty of +X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +X * GNU General Public License for more details. +X * +X * You should have received a copy of the GNU General Public License +X * along with this program; if not, write to the Free Software +X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +X * +X ********************************************************************/ +X +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/soundcard.h> +X +int main(int argc, char *argv[]) +{ +X int fd; +X +X if (argc != 2) { +X fprintf(stderr, "usage: msndreset <mixer device>\n"); +X exit(1); +X } +X +X if ((fd = open(argv[1], O_RDWR)) < 0) { +X perror(argv[1]); +X exit(1); +X } +X +X if (ioctl(fd, SOUND_MIXER_PRIVATE1, 0) < 0) { +X fprintf(stderr, "error: msnd ioctl reset failed\n"); +X perror("ioctl"); +X close(fd); +X exit(1); +X } +X +X close(fd); +X +X return 0; +} +SHAR_EOF + $shar_touch -am 1204100698 'MultiSound.d/msndreset.c' && + chmod 0664 'MultiSound.d/msndreset.c' || + $echo 'restore of' 'MultiSound.d/msndreset.c' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'MultiSound.d/msndreset.c:' 'MD5 check failed' +c52f876521084e8eb25e12e01dcccb8a MultiSound.d/msndreset.c +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/msndreset.c'`" + test 1491 -eq "$shar_count" || + $echo 'MultiSound.d/msndreset.c:' 'original size' '1491,' 'current size' "$shar_count!" + fi +fi +rm -fr _sh01426 +exit 0 diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index 7c2d37571af0..e06238131f77 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -34,6 +34,22 @@ ALC262 ====== inv-dmic Inverted internal mic workaround +fsc-h270 + Fixups for Fujitsu-Siemens Celsius H270 +fsc-s7110 + Fixups for Fujitsu-Siemens Lifebook S7110 +hp-z200 + Fixups for HP Z200 +tyan + Fixups for Tyan Thunder n6650W +lenovo-3000 + Fixups for Lenovo 3000 +benq + Fixups for Benq ED8 +benq-t31 + Fixups for Benq T31 +bayleybay + Fixups for Intel BayleyBay ALC267/268 ========== @@ -41,6 +57,8 @@ inv-dmic Inverted internal mic workaround hp-eapd Disable HP EAPD on NID 0x15 +spdif + Enable SPDIF output on NID 0x1e ALC22x/23x/25x/269/27x/28x/29x (and vendor-specific ALC3xxx models) =================================================================== @@ -70,6 +88,10 @@ dell-headset-multi Headset jack, which can also be used as mic-in dell-headset-dock Headset jack (without mic-in), and also dock I/O +dell-headset3 + Headset jack (without mic-in), and also dock I/O, variant 3 +dell-headset4 + Headset jack (without mic-in), and also dock I/O, variant 4 alc283-dac-wcaps Fixups for Chromebook with ALC283 alc283-sense-combo @@ -80,15 +102,173 @@ tpt440 Lenovo Thinkpad T440s setup tpt460 Lenovo Thinkpad T460/560 setup +tpt470-dock + Lenovo Thinkpad T470 dock setup dual-codecs Lenovo laptops with dual codecs alc700-ref Intel reference board with ALC700 codec +vaio + Pin fixups for Sony VAIO laptops +dell-m101z + COEF setup for Dell M101z +asus-g73jw + Subwoofer pin fixup for ASUS G73JW +lenovo-eapd + Inversed EAPD setup for Lenovo laptops +sony-hweq + H/W EQ COEF setup for Sony laptops +pcm44k + Fixed PCM 44kHz constraints (for buggy devices) +lifebook + Dock pin fixups for Fujitsu Lifebook +lifebook-extmic + Headset mic fixup for Fujitsu Lifebook +lifebook-hp-pin + Headphone pin fixup for Fujitsu Lifebook +lifebook-u7x7 + Lifebook U7x7 fixups +alc269vb-amic + ALC269VB analog mic pin fixups +alc269vb-dmic + ALC269VB digital mic pin fixups +hp-mute-led-mic1 + Mute LED via Mic1 pin on HP +hp-mute-led-mic2 + Mute LED via Mic2 pin on HP +hp-mute-led-mic3 + Mute LED via Mic3 pin on HP +hp-gpio-mic1 + GPIO + Mic1 pin LED on HP +hp-line1-mic1 + Mute LED via Line1 + Mic1 pins on HP +noshutup + Skip shutup callback +sony-nomic + Headset mic fixup for Sony laptops +aspire-headset-mic + Headset pin fixup for Acer Aspire +asus-x101 + ASUS X101 fixups +acer-ao7xx + Acer AO7xx fixups +acer-aspire-e1 + Acer Aspire E1 fixups +acer-ac700 + Acer AC700 fixups +limit-mic-boost + Limit internal mic boost on Lenovo machines +asus-zenbook + ASUS Zenbook fixups +asus-zenbook-ux31a + ASUS Zenbook UX31A fixups +ordissimo + Ordissimo EVE2 (or Malata PC-B1303) fixups +asus-tx300 + ASUS TX300 fixups +alc283-int-mic + ALC283 COEF setup for Lenovo machines +mono-speakers + Subwoofer and headset fixupes for Dell Inspiron +alc290-subwoofer + Subwoofer fixups for Dell Vostro +thinkpad + Binding with thinkpad_acpi driver for Lenovo machines +dmic-thinkpad + thinkpad_acpi binding + digital mic support +alc255-acer + ALC255 fixups on Acer machines +alc255-asus + ALC255 fixups on ASUS machines +alc255-dell1 + ALC255 fixups on Dell machines +alc255-dell2 + ALC255 fixups on Dell machines, variant 2 +alc293-dell1 + ALC293 fixups on Dell machines +alc283-headset + Headset pin fixups on ALC283 +aspire-v5 + Acer Aspire V5 fixups +hp-gpio4 + GPIO and Mic1 pin mute LED fixups for HP +hp-gpio-led + GPIO mute LEDs on HP +hp-gpio2-hotkey + GPIO mute LED with hot key handling on HP +hp-dock-pins + GPIO mute LEDs and dock support on HP +hp-dock-gpio-mic + GPIO, Mic mute LED and dock support on HP +hp-9480m + HP 9480m fixups +alc288-dell1 + ALC288 fixups on Dell machines +alc288-dell-xps13 + ALC288 fixups on Dell XPS13 +dell-e7x + Dell E7x fixups +alc293-dell + ALC293 fixups on Dell machines +alc298-dell1 + ALC298 fixups on Dell machines +alc298-dell-aio + ALC298 fixups on Dell AIO machines +alc275-dell-xps + ALC275 fixups on Dell XPS models +alc256-dell-xps13 + ALC256 fixups on Dell XPS13 +lenovo-spk-noise + Workaround for speaker noise on Lenovo machines +lenovo-hotkey + Hot-key support via Mic2 pin on Lenovo machines +dell-spk-noise + Workaround for speaker noise on Dell machines +alc255-dell1 + ALC255 fixups on Dell machines +alc295-disable-dac3 + Disable DAC3 routing on ALC295 +alc280-hp-headset + HP Elitebook fixups +alc221-hp-mic + Front mic pin fixup on HP machines +alc298-spk-volume + Speaker pin routing workaround on ALC298 +dell-inspiron-7559 + Dell Inspiron 7559 fixups +ativ-book + Samsung Ativ book 8 fixups +alc221-hp-mic + ALC221 headset fixups on HP machines +alc256-asus-mic + ALC256 fixups on ASUS machines +alc256-asus-aio + ALC256 fixups on ASUS AIO machines +alc233-eapd + ALC233 fixups on ASUS machines +alc294-lenovo-mic + ALC294 Mic pin fixup for Lenovo AIO machines +alc225-wyse + Dell Wyse fixups +alc274-dell-aio + ALC274 fixups on Dell AIO machines +alc255-dummy-lineout + Dell Precision 3930 fixups +alc255-dell-headset"}, + Dell Precision 3630 fixups +alc295-hp-x360 + HP Spectre X360 fixups ALC66x/67x/892 ============== +aspire + Subwoofer pin fixup for Aspire laptops +ideapad + Subwoofer pin fixup for Ideapad laptops mario Chromebook mario model fixup +hp-rp5800 + Headphone pin fixup for HP RP5800 asus-mode1 ASUS asus-mode2 @@ -105,10 +285,40 @@ asus-mode7 ASUS asus-mode8 ASUS +zotac-z68 + Front HP fixup for Zotac Z68 inv-dmic Inverted internal mic workaround +alc662-headset-multi + Dell headset jack, which can also be used as mic-in (ALC662) dell-headset-multi Headset jack, which can also be used as mic-in +alc662-headset + Headset mode support on ALC662 +alc668-headset + Headset mode support on ALC668 +bass16 + Bass speaker fixup on pin 0x16 +bass1a + Bass speaker fixup on pin 0x1a +automute + Auto-mute fixups for ALC668 +dell-xps13 + Dell XPS13 fixups +asus-nx50 + ASUS Nx50 fixups +asus-nx51 + ASUS Nx51 fixups +alc891-headset + Headset mode support on ALC891 +alc891-headset-multi + Dell headset jack, which can also be used as mic-in (ALC891) +acer-veriton + Acer Veriton speaker pin fixup +asrock-mobo + Fix invalid 0x15 / 0x16 pins +usi-headset + Headset support on USI machines dual-codecs Lenovo laptops with dual codecs @@ -116,20 +326,70 @@ ALC680 ====== N/A -ALC88x/898/1150 -====================== +ALC88x/898/1150/1220 +==================== +abit-aw9d + Pin fixups for Abit AW9D-MAX +lenovo-y530 + Pin fixups for Lenovo Y530 +acer-aspire-7736 + Fixup for Acer Aspire 7736 +asus-w90v + Pin fixup for ASUS W90V +cd + Enable audio CD pin NID 0x1c +no-front-hp + Disable front HP pin NID 0x1b +vaio-tt + Pin fixup for VAIO TT +eee1601 + COEF setups for ASUS Eee 1601 +alc882-eapd + Change EAPD COEF mode on ALC882 +alc883-eapd + Change EAPD COEF mode on ALC883 +gpio1 + Enable GPIO1 +gpio2 + Enable GPIO2 +gpio3 + Enable GPIO3 +alc889-coef + Setup ALC889 COEF +asus-w2jc + Fixups for ASUS W2JC acer-aspire-4930g Acer Aspire 4930G/5930G/6530G/6930G/7730G acer-aspire-8930g Acer Aspire 8330G/6935G acer-aspire Acer Aspire others +macpro-gpio + GPIO setup for Mac Pro +dac-route + Workaround for DAC routing on Acer Aspire +mbp-vref + Vref setup for Macbook Pro +imac91-vref + Vref setup for iMac 9,1 +mba11-vref + Vref setup for MacBook Air 1,1 +mba21-vref + Vref setup for MacBook Air 2,1 +mp11-vref + Vref setup for Mac Pro 1,1 +mp41-vref + Vref setup for Mac Pro 4,1 inv-dmic Inverted internal mic workaround no-primary-hp VAIO Z/VGC-LN51JGB workaround (for fixed speaker DAC) +asus-bass + Bass speaker setup for ASUS ET2700 dual-codecs ALC1220 dual codecs for Gaming mobos +clevo-p950 + Fixups for Clevo P950 ALC861/660 ========== diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index f1baaa88e766..21abc4da2549 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -8,6 +8,7 @@ #include <linux/device.h> #include <linux/interrupt.h> +#include <linux/pm_runtime.h> #include <linux/timecounter.h> #include <sound/core.h> #include <sound/memalloc.h> @@ -171,12 +172,38 @@ int snd_hdac_power_down(struct hdac_device *codec); int snd_hdac_power_up_pm(struct hdac_device *codec); int snd_hdac_power_down_pm(struct hdac_device *codec); int snd_hdac_keep_power_up(struct hdac_device *codec); + +/* call this at entering into suspend/resume callbacks in codec driver */ +static inline void snd_hdac_enter_pm(struct hdac_device *codec) +{ + atomic_inc(&codec->in_pm); +} + +/* call this at leaving from suspend/resume callbacks in codec driver */ +static inline void snd_hdac_leave_pm(struct hdac_device *codec) +{ + atomic_dec(&codec->in_pm); +} + +static inline bool snd_hdac_is_in_pm(struct hdac_device *codec) +{ + return atomic_read(&codec->in_pm); +} + +static inline bool snd_hdac_is_power_on(struct hdac_device *codec) +{ + return !pm_runtime_suspended(&codec->dev); +} #else static inline int snd_hdac_power_up(struct hdac_device *codec) { return 0; } static inline int snd_hdac_power_down(struct hdac_device *codec) { return 0; } static inline int snd_hdac_power_up_pm(struct hdac_device *codec) { return 0; } static inline int snd_hdac_power_down_pm(struct hdac_device *codec) { return 0; } static inline int snd_hdac_keep_power_up(struct hdac_device *codec) { return 0; } +static inline void snd_hdac_enter_pm(struct hdac_device *codec) {} +static inline void snd_hdac_leave_pm(struct hdac_device *codec) {} +static inline bool snd_hdac_is_in_pm(struct hdac_device *codec) { return 0; } +static inline bool snd_hdac_is_power_on(struct hdac_device *codec) { return 1; } #endif /* diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c index 31f858eceffc..7a0dfca03a57 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -13,6 +13,7 @@ #include <linux/idr.h> #include <linux/list.h> #include <linux/mutex.h> +#include <linux/of.h> #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/slab.h> @@ -68,6 +69,27 @@ ac97_codec_find(struct ac97_controller *ac97_ctrl, unsigned int codec_num) return ac97_ctrl->codecs[codec_num]; } +static struct device_node * +ac97_of_get_child_device(struct ac97_controller *ac97_ctrl, int idx, + unsigned int vendor_id) +{ + struct device_node *node; + u32 reg; + char compat[] = "ac97,0000,0000"; + + snprintf(compat, sizeof(compat), "ac97,%04x,%04x", + vendor_id >> 16, vendor_id & 0xffff); + + for_each_child_of_node(ac97_ctrl->parent->of_node, node) { + if ((idx != of_property_read_u32(node, "reg", ®)) || + !of_device_is_compatible(node, compat)) + continue; + return of_node_get(node); + } + + return NULL; +} + static void ac97_codec_release(struct device *dev) { struct ac97_codec_device *adev; @@ -76,6 +98,7 @@ static void ac97_codec_release(struct device *dev) adev = to_ac97_device(dev); ac97_ctrl = adev->ac97_ctrl; ac97_ctrl->codecs[adev->num] = NULL; + of_node_put(dev->of_node); kfree(adev); } @@ -98,6 +121,8 @@ static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx, device_initialize(&codec->dev); dev_set_name(&codec->dev, "%s:%u", dev_name(ac97_ctrl->parent), idx); + codec->dev.of_node = ac97_of_get_child_device(ac97_ctrl, idx, + vendor_id); ret = device_add(&codec->dev); if (ret) @@ -105,6 +130,7 @@ static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx, return 0; err_free_codec: + of_node_put(codec->dev.of_node); put_device(&codec->dev); kfree(codec); ac97_ctrl->codecs[idx] = NULL; diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c index 71960089e207..65557421fe0b 100644 --- a/sound/aoa/core/gpio-feature.c +++ b/sound/aoa/core/gpio-feature.c @@ -88,8 +88,10 @@ static struct device_node *get_gpio(char *name, } reg = of_get_property(np, "reg", NULL); - if (!reg) + if (!reg) { + of_node_put(np); return NULL; + } *gpioptr = *reg; diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c index 525b746330be..453fc29fade7 100644 --- a/sound/firewire/motu/motu-protocol-v2.c +++ b/sound/firewire/motu/motu-protocol-v2.c @@ -13,6 +13,8 @@ #define V2_CLOCK_RATE_SHIFT 3 #define V2_CLOCK_SRC_MASK 0x00000007 #define V2_CLOCK_SRC_SHIFT 0 +#define V2_CLOCK_TRAVELER_FETCH_DISABLE 0x04000000 +#define V2_CLOCK_TRAVELER_FETCH_ENABLE 0x03000000 #define V2_IN_OUT_CONF_OFFSET 0x0c04 #define V2_OPT_OUT_IFACE_MASK 0x00000c00 @@ -66,6 +68,11 @@ static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate) data &= ~V2_CLOCK_RATE_MASK; data |= i << V2_CLOCK_RATE_SHIFT; + if (motu->spec == &snd_motu_spec_traveler) { + data &= ~V2_CLOCK_TRAVELER_FETCH_ENABLE; + data |= V2_CLOCK_TRAVELER_FETCH_DISABLE; + } + reg = cpu_to_be32(data); return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, ®, sizeof(reg)); @@ -121,8 +128,31 @@ static int v2_get_clock_source(struct snd_motu *motu, static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable) { - /* V2 protocol doesn't have this feature. */ - return 0; + __be32 reg; + u32 data; + int err = 0; + + if (motu->spec == &snd_motu_spec_traveler) { + err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, + ®, sizeof(reg)); + if (err < 0) + return err; + data = be32_to_cpu(reg); + + data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE | + V2_CLOCK_TRAVELER_FETCH_ENABLE); + + if (enable) + data |= V2_CLOCK_TRAVELER_FETCH_ENABLE; + else + data |= V2_CLOCK_TRAVELER_FETCH_DISABLE; + + reg = cpu_to_be32(data); + err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, + ®, sizeof(reg)); + } + + return err; } static void calculate_fixed_part(struct snd_motu_packet_format *formats, @@ -149,11 +179,20 @@ static void calculate_fixed_part(struct snd_motu_packet_format *formats, pcm_chunks[1] += 2; } } else { - /* - * Packets to v2 units transfer main-out-1/2 and phone-out-1/2. - */ - pcm_chunks[0] += 4; - pcm_chunks[1] += 4; + if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) { + pcm_chunks[0] += 2; + pcm_chunks[1] += 2; + } + + // Packets to v2 units include 2 chunks for phone 1/2, except + // for 176.4/192.0 kHz. + pcm_chunks[0] += 2; + pcm_chunks[1] += 2; + } + + if (flags & SND_MOTU_SPEC_HAS_AESEBU_IFACE) { + pcm_chunks[0] += 2; + pcm_chunks[1] += 2; } /* @@ -164,19 +203,16 @@ static void calculate_fixed_part(struct snd_motu_packet_format *formats, pcm_chunks[0] += 2; pcm_chunks[1] += 2; - /* This part should be multiples of 4. */ - formats->fixed_part_pcm_chunks[0] = round_up(2 + pcm_chunks[0], 4) - 2; - formats->fixed_part_pcm_chunks[1] = round_up(2 + pcm_chunks[1], 4) - 2; - if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) - formats->fixed_part_pcm_chunks[2] = - round_up(2 + pcm_chunks[2], 4) - 2; + formats->fixed_part_pcm_chunks[0] = pcm_chunks[0]; + formats->fixed_part_pcm_chunks[1] = pcm_chunks[1]; + formats->fixed_part_pcm_chunks[2] = pcm_chunks[2]; } static void calculate_differed_part(struct snd_motu_packet_format *formats, enum snd_motu_spec_flags flags, u32 data, u32 mask, u32 shift) { - unsigned char pcm_chunks[3] = {0, 0}; + unsigned char pcm_chunks[2] = {0, 0}; /* * When optical interfaces are configured for S/PDIF (TOSLINK), diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c index c7cd9864dc4d..7cc80a05e91f 100644 --- a/sound/firewire/motu/motu-protocol-v3.c +++ b/sound/firewire/motu/motu-protocol-v3.c @@ -188,11 +188,20 @@ static void calculate_fixed_part(struct snd_motu_packet_format *formats, pcm_chunks[1] += 2; } } else { - /* - * Packets to v2 units transfer main-out-1/2 and phone-out-1/2. - */ - pcm_chunks[0] += 4; - pcm_chunks[1] += 4; + if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) { + pcm_chunks[0] += 2; + pcm_chunks[1] += 2; + } + + // Packets to v3 units include 2 chunks for phone 1/2, except + // for 176.4/192.0 kHz. + pcm_chunks[0] += 2; + pcm_chunks[1] += 2; + } + + if (flags & SND_MOTU_SPEC_HAS_AESEBU_IFACE) { + pcm_chunks[0] += 2; + pcm_chunks[1] += 2; } /* diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 0d6b526105ab..300d31b6f191 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -200,6 +200,22 @@ static const struct snd_motu_spec motu_828mk2 = { .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | SND_MOTU_SPEC_TX_MICINST_CHUNK | SND_MOTU_SPEC_TX_RETURN_CHUNK | + SND_MOTU_SPEC_RX_SEPARETED_MAIN | + SND_MOTU_SPEC_HAS_OPT_IFACE_A | + SND_MOTU_SPEC_RX_MIDI_2ND_Q | + SND_MOTU_SPEC_TX_MIDI_2ND_Q, + + .analog_in_ports = 8, + .analog_out_ports = 8, +}; + +const struct snd_motu_spec snd_motu_spec_traveler = { + .name = "Traveler", + .protocol = &snd_motu_protocol_v2, + .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | + SND_MOTU_SPEC_SUPPORT_CLOCK_X4 | + SND_MOTU_SPEC_TX_RETURN_CHUNK | + SND_MOTU_SPEC_HAS_AESEBU_IFACE | SND_MOTU_SPEC_HAS_OPT_IFACE_A | SND_MOTU_SPEC_RX_MIDI_2ND_Q | SND_MOTU_SPEC_TX_MIDI_2ND_Q, @@ -216,6 +232,7 @@ static const struct snd_motu_spec motu_828mk3 = { SND_MOTU_SPEC_TX_MICINST_CHUNK | SND_MOTU_SPEC_TX_RETURN_CHUNK | SND_MOTU_SPEC_TX_REVERB_CHUNK | + SND_MOTU_SPEC_RX_SEPARETED_MAIN | SND_MOTU_SPEC_HAS_OPT_IFACE_A | SND_MOTU_SPEC_HAS_OPT_IFACE_B | SND_MOTU_SPEC_RX_MIDI_3RD_Q | @@ -231,6 +248,7 @@ static const struct snd_motu_spec motu_audio_express = { .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | SND_MOTU_SPEC_TX_MICINST_CHUNK | SND_MOTU_SPEC_TX_RETURN_CHUNK | + SND_MOTU_SPEC_RX_SEPARETED_MAIN | SND_MOTU_SPEC_RX_MIDI_2ND_Q | SND_MOTU_SPEC_TX_MIDI_3RD_Q, .analog_in_ports = 2, @@ -250,6 +268,7 @@ static const struct snd_motu_spec motu_audio_express = { static const struct ieee1394_device_id motu_id_table[] = { SND_MOTU_DEV_ENTRY(0x101800, &motu_828mk2), + SND_MOTU_DEV_ENTRY(0x107800, &snd_motu_spec_traveler), SND_MOTU_DEV_ENTRY(0x106800, &motu_828mk3), /* FireWire only. */ SND_MOTU_DEV_ENTRY(0x100800, &motu_828mk3), /* Hybrid. */ SND_MOTU_DEV_ENTRY(0x104800, &motu_audio_express), diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index 4b23cf337c4b..fd5327d30ab1 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -79,13 +79,14 @@ enum snd_motu_spec_flags { SND_MOTU_SPEC_TX_MICINST_CHUNK = 0x0004, SND_MOTU_SPEC_TX_RETURN_CHUNK = 0x0008, SND_MOTU_SPEC_TX_REVERB_CHUNK = 0x0010, - SND_MOTU_SPEC_TX_AESEBU_CHUNK = 0x0020, + SND_MOTU_SPEC_HAS_AESEBU_IFACE = 0x0020, SND_MOTU_SPEC_HAS_OPT_IFACE_A = 0x0040, SND_MOTU_SPEC_HAS_OPT_IFACE_B = 0x0080, SND_MOTU_SPEC_RX_MIDI_2ND_Q = 0x0100, SND_MOTU_SPEC_RX_MIDI_3RD_Q = 0x0200, SND_MOTU_SPEC_TX_MIDI_2ND_Q = 0x0400, SND_MOTU_SPEC_TX_MIDI_3RD_Q = 0x0800, + SND_MOTU_SPEC_RX_SEPARETED_MAIN = 0x1000, }; #define SND_MOTU_CLOCK_RATE_COUNT 6 @@ -128,6 +129,8 @@ struct snd_motu_spec { extern const struct snd_motu_protocol snd_motu_protocol_v2; extern const struct snd_motu_protocol snd_motu_protocol_v3; +extern const struct snd_motu_spec snd_motu_spec_traveler; + int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, const struct snd_motu_protocol *const protocol); diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 43b35a873d78..d7db1eeebc84 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -459,7 +459,7 @@ config SND_MSND_CLASSIC Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or Monterey (not for the Pinnacle or Fiji). - See <file:Documentation/sound/oss/MultiSound> for important information + See <file:Documentation/sound/cards/multisound.sh> for important information about this driver. Note that it has been discontinued, but the Voyetra Turtle Beach knowledge base entry for it is still available at <http://www.turtlebeach.com/site/kb_ftp/790.asp>. diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index db710d0a609f..4777d50fbbf8 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c @@ -938,17 +938,18 @@ static int ct_mixer_topology_build(struct ct_mixer *mixer) struct sum *sum; struct amixer *amix_d, *amix_s; enum CT_AMIXER_CTL i, j; + enum CT_SUM_CTL k; /* Build topology from destination to source */ /* Set up Master mixer */ - for (i = AMIXER_MASTER_F, j = SUM_IN_F; - i <= AMIXER_MASTER_S; i++, j++) { + for (i = AMIXER_MASTER_F, k = SUM_IN_F; + i <= AMIXER_MASTER_S; i++, k++) { amix_d = mixer->amixers[i*CHN_NUM]; - sum = mixer->sums[j*CHN_NUM]; + sum = mixer->sums[k*CHN_NUM]; amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); amix_d = mixer->amixers[i*CHN_NUM+1]; - sum = mixer->sums[j*CHN_NUM+1]; + sum = mixer->sums[k*CHN_NUM+1]; amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); } @@ -972,12 +973,12 @@ static int ct_mixer_topology_build(struct ct_mixer *mixer) amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); /* Set up PCM-in mixer */ - for (i = AMIXER_PCM_F, j = SUM_IN_F; i <= AMIXER_PCM_S; i++, j++) { + for (i = AMIXER_PCM_F, k = SUM_IN_F; i <= AMIXER_PCM_S; i++, k++) { amix_d = mixer->amixers[i*CHN_NUM]; - sum = mixer->sums[j*CHN_NUM]; + sum = mixer->sums[k*CHN_NUM]; amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); amix_d = mixer->amixers[i*CHN_NUM+1]; - sum = mixer->sums[j*CHN_NUM+1]; + sum = mixer->sums[k*CHN_NUM+1]; amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); } diff --git a/sound/pci/hda/dell_wmi_helper.c b/sound/pci/hda/dell_wmi_helper.c index 1b48a8c19d28..8a7dbd1a7fbf 100644 --- a/sound/pci/hda/dell_wmi_helper.c +++ b/sound/pci/hda/dell_wmi_helper.c @@ -6,111 +6,18 @@ #if IS_ENABLED(CONFIG_DELL_LAPTOP) #include <linux/dell-led.h> -enum { - MICMUTE_LED_ON, - MICMUTE_LED_OFF, - MICMUTE_LED_FOLLOW_CAPTURE, - MICMUTE_LED_FOLLOW_MUTE, -}; - -static int dell_led_mode = MICMUTE_LED_FOLLOW_MUTE; -static int dell_capture; -static int dell_led_value; static int (*dell_micmute_led_set_func)(int); -static void (*dell_old_cap_hook)(struct hda_codec *, - struct snd_kcontrol *, - struct snd_ctl_elem_value *); - -static void call_micmute_led_update(void) -{ - int val; - - switch (dell_led_mode) { - case MICMUTE_LED_ON: - val = 1; - break; - case MICMUTE_LED_OFF: - val = 0; - break; - case MICMUTE_LED_FOLLOW_CAPTURE: - val = dell_capture; - break; - case MICMUTE_LED_FOLLOW_MUTE: - default: - val = !dell_capture; - break; - } - - if (val == dell_led_value) - return; - dell_led_value = val; - dell_micmute_led_set_func(dell_led_value); -} - -static void update_dell_wmi_micmute_led(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - if (dell_old_cap_hook) - dell_old_cap_hook(codec, kcontrol, ucontrol); - - if (!ucontrol || !dell_micmute_led_set_func) - return; - if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) { - /* TODO: How do I verify if it's a mono or stereo here? */ - dell_capture = (ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]); - call_micmute_led_update(); - } -} -static int dell_mic_mute_led_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static void dell_micmute_update(struct hda_codec *codec) { - static const char * const texts[] = { - "On", "Off", "Follow Capture", "Follow Mute", - }; - - return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); -} + struct hda_gen_spec *spec = codec->spec; -static int dell_mic_mute_led_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = dell_led_mode; - return 0; + dell_micmute_led_set_func(spec->micmute_led.led_value); } -static int dell_mic_mute_led_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int mode; - - mode = ucontrol->value.enumerated.item[0]; - if (mode > MICMUTE_LED_FOLLOW_MUTE) - mode = MICMUTE_LED_FOLLOW_MUTE; - if (mode == dell_led_mode) - return 0; - dell_led_mode = mode; - call_micmute_led_update(); - return 1; -} - -static const struct snd_kcontrol_new dell_mic_mute_mode_ctls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic Mute-LED Mode", - .info = dell_mic_mute_led_mode_info, - .get = dell_mic_mute_led_mode_get, - .put = dell_mic_mute_led_mode_put, - }, - {} -}; - static void alc_fixup_dell_wmi(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - struct alc_spec *spec = codec->spec; bool removefunc = false; if (action == HDA_FIXUP_ACT_PROBE) { @@ -121,25 +28,14 @@ static void alc_fixup_dell_wmi(struct hda_codec *codec, return; } - removefunc = true; - if (dell_micmute_led_set_func(false) >= 0) { - dell_led_value = 0; - if (spec->gen.num_adc_nids > 1 && !spec->gen.dyn_adc_switch) - codec_dbg(codec, "Skipping micmute LED control due to several ADCs"); - else { - dell_old_cap_hook = spec->gen.cap_sync_hook; - spec->gen.cap_sync_hook = update_dell_wmi_micmute_led; - removefunc = false; - add_mixer(spec, dell_mic_mute_mode_ctls); - } - } - + removefunc = (dell_micmute_led_set_func(false) < 0) || + (snd_hda_gen_add_micmute_led(codec, + dell_micmute_update) <= 0); } if (dell_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) { symbol_put(dell_micmute_led_set); dell_micmute_led_set_func = NULL; - dell_old_cap_hook = NULL; } } diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 059cfade05cc..ffe7911e6586 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -37,15 +37,8 @@ #include "hda_jack.h" #include <sound/hda_hwdep.h> -#ifdef CONFIG_PM -#define codec_in_pm(codec) atomic_read(&(codec)->core.in_pm) -#define hda_codec_is_power_on(codec) \ - (!pm_runtime_suspended(hda_codec_dev(codec))) -#else -#define codec_in_pm(codec) 0 -#define hda_codec_is_power_on(codec) 1 -#endif - +#define codec_in_pm(codec) snd_hdac_is_in_pm(&codec->core) +#define hda_codec_is_power_on(codec) snd_hdac_is_power_on(&codec->core) #define codec_has_epss(codec) \ ((codec)->core.power_caps & AC_PWRST_EPSS) #define codec_has_clkstop(codec) \ @@ -2878,14 +2871,13 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec) { unsigned int state; - atomic_inc(&codec->core.in_pm); - + snd_hdac_enter_pm(&codec->core); if (codec->patch_ops.suspend) codec->patch_ops.suspend(codec); hda_cleanup_all_streams(codec); state = hda_set_power_state(codec, AC_PWRST_D3); update_power_acct(codec, true); - atomic_dec(&codec->core.in_pm); + snd_hdac_leave_pm(&codec->core); return state; } @@ -2894,8 +2886,7 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec) */ static void hda_call_codec_resume(struct hda_codec *codec) { - atomic_inc(&codec->core.in_pm); - + snd_hdac_enter_pm(&codec->core); if (codec->core.regmap) regcache_mark_dirty(codec->core.regmap); @@ -2918,7 +2909,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_jackpoll_work(&codec->jackpoll_work.work); else snd_hda_jack_report_sync(codec); - atomic_dec(&codec->core.in_pm); + snd_hdac_leave_pm(&codec->core); } static int hda_codec_runtime_suspend(struct device *dev) @@ -3876,7 +3867,7 @@ EXPORT_SYMBOL_GPL(snd_hda_correct_pin_ctl); * This function is a helper to set a pin ctl value more safely. * It corrects the pin ctl value via snd_hda_correct_pin_ctl(), stores the * value in pin target array via snd_hda_codec_set_pin_target(), then - * actually writes the value via either snd_hda_codec_update_cache() or + * actually writes the value via either snd_hda_codec_write_cache() or * snd_hda_codec_write() depending on @cached flag. */ int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, @@ -3885,7 +3876,7 @@ int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, val = snd_hda_correct_pin_ctl(codec, pin, val); snd_hda_codec_set_pin_target(codec, pin, val); if (cached) - return snd_hda_codec_update_cache(codec, pin, 0, + return snd_hda_codec_write_cache(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); else return snd_hda_codec_write(codec, pin, 0, diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 8bbedf7f3f54..c3e97f558620 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -84,6 +84,7 @@ struct hda_bus { */ typedef int (*hda_codec_patch_t)(struct hda_codec *); +#define HDA_CODEC_ID_SKIP_PROBE 0x00000001 #define HDA_CODEC_ID_GENERIC_HDMI 0x00000101 #define HDA_CODEC_ID_GENERIC 0x00000201 @@ -383,9 +384,6 @@ snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, return snd_hdac_regmap_write(&codec->core, nid, verb, parm); } -#define snd_hda_codec_update_cache(codec, nid, flags, verb, parm) \ - snd_hda_codec_write_cache(codec, nid, flags, verb, parm) - /* the struct for codec->pin_configs */ struct hda_pincfg { hda_nid_t nid; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index db773e219aaa..579984ecdec3 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -209,7 +209,7 @@ static void parse_user_hints(struct hda_codec *codec) */ #define update_pin_ctl(codec, pin, val) \ - snd_hda_codec_update_cache(codec, pin, 0, \ + snd_hda_codec_write_cache(codec, pin, 0, \ AC_VERB_SET_PIN_WIDGET_CONTROL, val) /* restore the pinctl based on the cached value */ @@ -898,7 +898,7 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, hda_nid_t nid = path->path[i]; if (enable && path->multi[i]) - snd_hda_codec_update_cache(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, path->idx[i]); if (has_amp_in(codec, path, i)) @@ -930,7 +930,7 @@ static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) return; if (codec->inv_eapd) enable = !enable; - snd_hda_codec_update_cache(codec, pin, 0, + snd_hda_codec_write_cache(codec, pin, 0, AC_VERB_SET_EAPD_BTLENABLE, enable ? 0x02 : 0x00); } @@ -3900,6 +3900,142 @@ static int parse_mic_boost(struct hda_codec *codec) } /* + * mic mute LED hook helpers + */ +enum { + MICMUTE_LED_ON, + MICMUTE_LED_OFF, + MICMUTE_LED_FOLLOW_CAPTURE, + MICMUTE_LED_FOLLOW_MUTE, +}; + +static void call_micmute_led_update(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + unsigned int val; + + switch (spec->micmute_led.led_mode) { + case MICMUTE_LED_ON: + val = 1; + break; + case MICMUTE_LED_OFF: + val = 0; + break; + case MICMUTE_LED_FOLLOW_CAPTURE: + val = !!spec->micmute_led.capture; + break; + case MICMUTE_LED_FOLLOW_MUTE: + default: + val = !spec->micmute_led.capture; + break; + } + + if (val == spec->micmute_led.led_value) + return; + spec->micmute_led.led_value = val; + if (spec->micmute_led.update) + spec->micmute_led.update(codec); +} + +static void update_micmute_led(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_gen_spec *spec = codec->spec; + unsigned int mask; + + if (spec->micmute_led.old_hook) + spec->micmute_led.old_hook(codec, kcontrol, ucontrol); + + if (!ucontrol) + return; + mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + if (!strcmp("Capture Switch", ucontrol->id.name)) { + /* TODO: How do I verify if it's a mono or stereo here? */ + if (ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]) + spec->micmute_led.capture |= mask; + else + spec->micmute_led.capture &= ~mask; + call_micmute_led_update(codec); + } +} + +static int micmute_led_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[] = { + "On", "Off", "Follow Capture", "Follow Mute", + }; + + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); +} + +static int micmute_led_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->micmute_led.led_mode; + return 0; +} + +static int micmute_led_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + unsigned int mode; + + mode = ucontrol->value.enumerated.item[0]; + if (mode > MICMUTE_LED_FOLLOW_MUTE) + mode = MICMUTE_LED_FOLLOW_MUTE; + if (mode == spec->micmute_led.led_mode) + return 0; + spec->micmute_led.led_mode = mode; + call_micmute_led_update(codec); + return 1; +} + +static const struct snd_kcontrol_new micmute_led_mode_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Mute-LED Mode", + .info = micmute_led_mode_info, + .get = micmute_led_mode_get, + .put = micmute_led_mode_put, +}; + +/** + * snd_hda_gen_add_micmute_led - helper for setting up mic mute LED hook + * @codec: the HDA codec + * @hook: the callback for updating LED + * + * Called from the codec drivers for offering the mic mute LED controls. + * When established, it sets up cap_sync_hook and triggers the callback at + * each time when the capture mixer switch changes. The callback is supposed + * to update the LED accordingly. + * + * Returns 0 if the hook is established or a negative error code. + */ +int snd_hda_gen_add_micmute_led(struct hda_codec *codec, + void (*hook)(struct hda_codec *)) +{ + struct hda_gen_spec *spec = codec->spec; + + spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE; + spec->micmute_led.capture = 0; + spec->micmute_led.led_value = 0; + spec->micmute_led.old_hook = spec->cap_sync_hook; + spec->micmute_led.update = hook; + spec->cap_sync_hook = update_micmute_led; + if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl)) + return -ENOMEM; + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led); + +/* * parse digital I/Os and set up NIDs in BIOS auto-parse mode */ static void parse_digital(struct hda_codec *codec) @@ -5837,7 +5973,7 @@ static void clear_unsol_on_unused_pins(struct hda_codec *codec) hda_nid_t nid = pin->nid; if (is_jack_detectable(codec, nid) && !snd_hda_jack_tbl_get(codec, nid)) - snd_hda_codec_update_cache(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, 0); } } diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 61772317de46..10123664fa61 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -86,6 +86,16 @@ struct badness_table { extern const struct badness_table hda_main_out_badness; extern const struct badness_table hda_extra_out_badness; +struct hda_micmute_hook { + unsigned int led_mode; + unsigned int capture; + unsigned int led_value; + void (*update)(struct hda_codec *codec); + void (*old_hook)(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +}; + struct hda_gen_spec { char stream_name_analog[32]; /* analog PCM stream */ const struct hda_pcm_stream *stream_analog_playback; @@ -276,6 +286,9 @@ struct hda_gen_spec { struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); + /* mic mute LED hook; called via cap_sync_hook */ + struct hda_micmute_hook micmute_led; + /* PCM hooks */ void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo, struct hda_codec *codec, @@ -342,4 +355,7 @@ unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on); int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin); +int snd_hda_gen_add_micmute_led(struct hda_codec *codec, + void (*hook)(struct hda_codec *)); + #endif /* __SOUND_HDA_GENERIC_H */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1ae1850b3bfd..a9b55d65f2bd 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2535,7 +2535,8 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, /* AMD Raven */ { PCI_DEVICE(0x1022, 0x15e3), - .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, + .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB | + AZX_DCAPS_PM_RUNTIME }, /* ATI HDMI */ { PCI_DEVICE(0x1002, 0x0002), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 757857313426..fd476fb40e1b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -148,7 +148,7 @@ static void ad_vmaster_eapd_hook(void *private_data, int enabled) return; if (codec->inv_eapd) enabled = !enabled; - snd_hda_codec_update_cache(codec, spec->eapd_nid, 0, + snd_hda_codec_write_cache(codec, spec->eapd_nid, 0, AC_VERB_SET_EAPD_BTLENABLE, enabled ? 0x02 : 0x00); } @@ -991,7 +991,7 @@ static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled) if (spec->eapd_nid) ad_vmaster_eapd_hook(private_data, enabled); - snd_hda_codec_update_cache(codec, 0x01, 0, + snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, enabled ? 0x00 : 0x02); } diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 04e949aa01ad..d62c56feaf7d 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -991,6 +991,7 @@ struct ca0132_spec { enum { QUIRK_NONE, QUIRK_ALIENWARE, + QUIRK_ALIENWARE_M17XR4, QUIRK_SBZ, QUIRK_R3DI, }; @@ -1040,6 +1041,7 @@ static const struct hda_pintbl r3di_pincfgs[] = { }; static const struct snd_pci_quirk ca0132_quirks[] = { + SND_PCI_QUIRK(0x1028, 0x057b, "Alienware M17x R4", QUIRK_ALIENWARE_M17XR4), SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE), SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE), SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE), @@ -5966,7 +5968,7 @@ static int ca0132_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; /* With the DSP enabled, desktops don't use this ADC. */ - if (spec->use_alt_functions) { + if (!spec->use_alt_functions) { info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2"); if (!info) return -ENOMEM; @@ -6130,7 +6132,10 @@ static void ca0132_init_dmic(struct hda_codec *codec) * Bit 6: set to select Data2, clear for Data1 * Bit 7: set to enable DMic, clear for AMic */ - val = 0x23; + if (spec->quirk == QUIRK_ALIENWARE_M17XR4) + val = 0x33; + else + val = 0x23; /* keep a copy of dmic ctl val for enable/disable dmic purpuse */ spec->dmic_ctl = val; snd_hda_codec_write(codec, spec->input_pins[0], 0, @@ -7223,7 +7228,7 @@ static int ca0132_init(struct hda_codec *codec) snd_hda_sequence_write(codec, spec->base_init_verbs); - if (spec->quirk != QUIRK_NONE) + if (spec->use_alt_functions) ca0132_alt_init(codec); ca0132_download_dsp(codec); @@ -7237,8 +7242,9 @@ static int ca0132_init(struct hda_codec *codec) case QUIRK_R3DI: r3di_setup_defaults(codec); break; - case QUIRK_NONE: - case QUIRK_ALIENWARE: + case QUIRK_SBZ: + break; + default: ca0132_setup_defaults(codec); ca0132_init_analog_mic2(codec); ca0132_init_dmic(codec); @@ -7343,7 +7349,6 @@ static const struct hda_codec_ops ca0132_patch_ops = { static void ca0132_config(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; spec->dacs[0] = 0x2; spec->dacs[1] = 0x3; @@ -7405,12 +7410,7 @@ static void ca0132_config(struct hda_codec *codec) /* SPDIF I/O */ spec->dig_out = 0x05; spec->multiout.dig_out_nid = spec->dig_out; - cfg->dig_out_pins[0] = 0x0c; - cfg->dig_outs = 1; - cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF; spec->dig_in = 0x09; - cfg->dig_in_pin = 0x0e; - cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; break; case QUIRK_R3DI: codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__); @@ -7438,9 +7438,6 @@ static void ca0132_config(struct hda_codec *codec) /* SPDIF I/O */ spec->dig_out = 0x05; spec->multiout.dig_out_nid = spec->dig_out; - cfg->dig_out_pins[0] = 0x0c; - cfg->dig_outs = 1; - cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF; break; default: spec->num_outputs = 2; @@ -7463,12 +7460,7 @@ static void ca0132_config(struct hda_codec *codec) /* SPDIF I/O */ spec->dig_out = 0x05; spec->multiout.dig_out_nid = spec->dig_out; - cfg->dig_out_pins[0] = 0x0c; - cfg->dig_outs = 1; - cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF; spec->dig_in = 0x09; - cfg->dig_in_pin = 0x0e; - cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; break; } } @@ -7476,7 +7468,7 @@ static void ca0132_config(struct hda_codec *codec) static int ca0132_prepare_verbs(struct hda_codec *codec) { /* Verbs + terminator (an empty element) */ -#define NUM_SPEC_VERBS 4 +#define NUM_SPEC_VERBS 2 struct ca0132_spec *spec = codec->spec; spec->chip_init_verbs = ca0132_init_verbs0; @@ -7488,34 +7480,24 @@ static int ca0132_prepare_verbs(struct hda_codec *codec) if (!spec->spec_init_verbs) return -ENOMEM; - /* HP jack autodetection */ - spec->spec_init_verbs[0].nid = spec->unsol_tag_hp; - spec->spec_init_verbs[0].param = AC_VERB_SET_UNSOLICITED_ENABLE; - spec->spec_init_verbs[0].verb = AC_USRSP_EN | spec->unsol_tag_hp; - - /* MIC1 jack autodetection */ - spec->spec_init_verbs[1].nid = spec->unsol_tag_amic1; - spec->spec_init_verbs[1].param = AC_VERB_SET_UNSOLICITED_ENABLE; - spec->spec_init_verbs[1].verb = AC_USRSP_EN | spec->unsol_tag_amic1; - /* config EAPD */ - spec->spec_init_verbs[2].nid = 0x0b; - spec->spec_init_verbs[2].param = 0x78D; - spec->spec_init_verbs[2].verb = 0x00; + spec->spec_init_verbs[0].nid = 0x0b; + spec->spec_init_verbs[0].param = 0x78D; + spec->spec_init_verbs[0].verb = 0x00; /* Previously commented configuration */ /* - spec->spec_init_verbs[3].nid = 0x0b; - spec->spec_init_verbs[3].param = AC_VERB_SET_EAPD_BTLENABLE; + spec->spec_init_verbs[2].nid = 0x0b; + spec->spec_init_verbs[2].param = AC_VERB_SET_EAPD_BTLENABLE; + spec->spec_init_verbs[2].verb = 0x02; + + spec->spec_init_verbs[3].nid = 0x10; + spec->spec_init_verbs[3].param = 0x78D; spec->spec_init_verbs[3].verb = 0x02; spec->spec_init_verbs[4].nid = 0x10; - spec->spec_init_verbs[4].param = 0x78D; + spec->spec_init_verbs[4].param = AC_VERB_SET_EAPD_BTLENABLE; spec->spec_init_verbs[4].verb = 0x02; - - spec->spec_init_verbs[5].nid = 0x10; - spec->spec_init_verbs[5].param = AC_VERB_SET_EAPD_BTLENABLE; - spec->spec_init_verbs[5].verb = 0x02; */ /* Terminator: spec->spec_init_verbs[NUM_SPEC_VERBS-1] */ diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index d6e079f4ec09..a7f91be45194 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1096,25 +1096,6 @@ static int cs421x_init(struct hda_codec *codec) return 0; } -static int cs421x_build_controls(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int err; - - err = snd_hda_gen_build_controls(codec); - if (err < 0) - return err; - - if (spec->gen.autocfg.speaker_outs && - spec->vendor_nid == CS4210_VENDOR_NID) { - err = snd_hda_ctl_add(codec, 0, - snd_ctl_new1(&cs421x_speaker_boost_ctl, codec)); - if (err < 0) - return err; - } - return 0; -} - static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) { unsigned int caps; @@ -1144,6 +1125,14 @@ static int cs421x_parse_auto_config(struct hda_codec *codec) return err; parse_cs421x_digital(codec); + + if (spec->gen.autocfg.speaker_outs && + spec->vendor_nid == CS4210_VENDOR_NID) { + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, + &cs421x_speaker_boost_ctl)) + return -ENOMEM; + } + return 0; } @@ -1175,7 +1164,7 @@ static int cs421x_suspend(struct hda_codec *codec) #endif static const struct hda_codec_ops cs421x_patch_ops = { - .build_controls = cs421x_build_controls, + .build_controls = snd_hda_gen_build_controls, .build_pcms = snd_hda_gen_build_pcms, .init = cs421x_init, .free = cs_free, diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e7fcfc3b8885..8b48352689b4 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -37,8 +37,6 @@ struct conexant_spec { struct hda_gen_spec gen; - unsigned int beep_amp; - /* extra EAPD pins */ unsigned int num_eapds; hda_nid_t eapds[4]; @@ -62,65 +60,48 @@ struct conexant_spec { #ifdef CONFIG_SND_HDA_INPUT_BEEP -static inline void set_beep_amp(struct conexant_spec *spec, hda_nid_t nid, - int idx, int dir) -{ - spec->gen.beep_nid = nid; - spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); -} -/* additional beep mixers; the actual parameters are overwritten at build */ +/* additional beep mixers; private_value will be overwritten */ static const struct snd_kcontrol_new cxt_beep_mixer[] = { HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), - { } /* end */ }; -/* create beep controls if needed */ -static int add_beep_ctls(struct hda_codec *codec) +static int set_beep_amp(struct conexant_spec *spec, hda_nid_t nid, + int idx, int dir) { - struct conexant_spec *spec = codec->spec; - int err; + struct snd_kcontrol_new *knew; + unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); + int i; - if (spec->beep_amp) { - const struct snd_kcontrol_new *knew; - for (knew = cxt_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; - } + spec->gen.beep_nid = nid; + for (i = 0; i < ARRAY_SIZE(cxt_beep_mixer); i++) { + knew = snd_hda_gen_add_kctl(&spec->gen, NULL, + &cxt_beep_mixer[i]); + if (!knew) + return -ENOMEM; + knew->private_value = beep_amp; } return 0; } -#else -#define set_beep_amp(spec, nid, idx, dir) /* NOP */ -#define add_beep_ctls(codec) 0 -#endif - -/* - * Automatic parser for CX20641 & co - */ -#ifdef CONFIG_SND_HDA_INPUT_BEEP -static void cx_auto_parse_beep(struct hda_codec *codec) +static int cx_auto_parse_beep(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; hda_nid_t nid; for_each_hda_codec_node(nid, codec) - if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) { - set_beep_amp(spec, nid, 0, HDA_OUTPUT); - break; - } + if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) + return set_beep_amp(spec, nid, 0, HDA_OUTPUT); + return 0; } #else -#define cx_auto_parse_beep(codec) +#define cx_auto_parse_beep(codec) 0 #endif +/* + * Automatic parser for CX20641 & co + */ + /* parse EAPDs */ static void cx_auto_parse_eapd(struct hda_codec *codec) { @@ -179,21 +160,6 @@ static void cx_auto_vmaster_hook_mute_led(void *private_data, int enabled) enabled ? 0x00 : 0x02); } -static int cx_auto_build_controls(struct hda_codec *codec) -{ - int err; - - err = snd_hda_gen_build_controls(codec); - if (err < 0) - return err; - - err = add_beep_ctls(codec); - if (err < 0) - return err; - - return 0; -} - static int cx_auto_init(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -234,7 +200,7 @@ static void cx_auto_free(struct hda_codec *codec) } static const struct hda_codec_ops cx_auto_patch_ops = { - .build_controls = cx_auto_build_controls, + .build_controls = snd_hda_gen_build_controls, .build_pcms = snd_hda_gen_build_pcms, .init = cx_auto_init, .reboot_notify = cx_auto_reboot_notify, @@ -343,6 +309,7 @@ static void cxt_fixup_headphone_mic(struct hda_codec *codec, snd_hdac_regmap_add_vendor_verb(&codec->core, 0x410); break; case HDA_FIXUP_ACT_PROBE: + WARN_ON(spec->gen.cap_sync_hook); spec->gen.cap_sync_hook = cxt_update_headset_mode_hook; spec->gen.automute_hook = cxt_update_headset_mode; break; @@ -374,7 +341,7 @@ static void cxt_fixup_headset_mic(struct hda_codec *codec, * control. */ #define update_mic_pin(codec, nid, val) \ - snd_hda_codec_update_cache(codec, nid, 0, \ + snd_hda_codec_write_cache(codec, nid, 0, \ AC_VERB_SET_PIN_WIDGET_CONTROL, val) static const struct hda_input_mux olpc_xo_dc_bias = { @@ -695,16 +662,12 @@ static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled) } /* turn on/off mic-mute LED via GPIO per capture hook */ -static void cxt_fixup_gpio_mic_mute_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void cxt_gpio_micmute_update(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - if (ucontrol) - cxt_update_gpio_led(codec, spec->gpio_mic_led_mask, - ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]); + cxt_update_gpio_led(codec, spec->gpio_mic_led_mask, + spec->gen.micmute_led.led_value); } @@ -721,11 +684,11 @@ static void cxt_fixup_mute_led_gpio(struct hda_codec *codec, if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = cxt_fixup_gpio_mic_mute_hook; spec->gpio_led = 0; spec->mute_led_polarity = 0; spec->gpio_mute_led_mask = 0x01; spec->gpio_mic_led_mask = 0x02; + snd_hda_gen_add_micmute_led(codec, cxt_gpio_micmute_update); } snd_hda_add_verbs(codec, gpio_init); if (spec->gpio_led) @@ -1036,7 +999,6 @@ static int patch_conexant_auto(struct hda_codec *codec) codec->spec = spec; codec->patch_ops = cx_auto_patch_ops; - cx_auto_parse_beep(codec); cx_auto_parse_eapd(codec); spec->gen.own_eapd_ctl = 1; if (spec->dynamic_eapd) @@ -1096,6 +1058,10 @@ static int patch_conexant_auto(struct hda_codec *codec) if (err < 0) goto error; + err = cx_auto_parse_beep(codec); + if (err < 0) + goto error; + /* Some laptops with Conexant chips show stalls in S3 resume, * which falls into the single-cmd mode. * Better to make reset, then. diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 8840daf9c6a3..cbf5f4e30027 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2489,7 +2489,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) return; /* ditto during suspend/resume process itself */ - if (atomic_read(&(codec)->core.in_pm)) + if (snd_hdac_is_in_pm(&codec->core)) return; snd_hdac_i915_set_bclk(&codec->bus->core); @@ -2542,6 +2542,8 @@ static int alloc_intel_hdmi(struct hda_codec *codec) /* requires i915 binding */ if (!codec->bus->core.audio_component) { codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); + /* set probe_id here to prevent generic fallback binding */ + codec->probe_id = HDA_CODEC_ID_SKIP_PROBE; return -ENODEV; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e9bd33ea538f..003e2c90e792 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -43,11 +43,9 @@ /* extra amp-initialization sequence types */ enum { + ALC_INIT_UNDEFINED, ALC_INIT_NONE, ALC_INIT_DEFAULT, - ALC_INIT_GPIO1, - ALC_INIT_GPIO2, - ALC_INIT_GPIO3, }; enum { @@ -85,19 +83,20 @@ struct alc_spec { struct hda_gen_spec gen; /* must be at head */ /* codec parameterization */ - const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ - unsigned int num_mixers; - unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ - struct alc_customize_define cdefine; unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ + /* GPIO bits */ + unsigned int gpio_mask; + unsigned int gpio_dir; + unsigned int gpio_data; + bool gpio_write_delay; /* add a delay before writing gpio_data */ + /* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */ int mute_led_polarity; hda_nid_t mute_led_nid; hda_nid_t cap_mute_led_nid; - unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */ unsigned int gpio_mute_led_mask; unsigned int gpio_mic_led_mask; @@ -205,41 +204,87 @@ static void alc_process_coef_fw(struct hda_codec *codec, } /* - * 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(). + * GPIO setup tables, used in initialization */ -static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix) + +/* Enable GPIO mask and set output */ +static void alc_setup_gpio(struct hda_codec *codec, unsigned int mask) +{ + struct alc_spec *spec = codec->spec; + + spec->gpio_mask |= mask; + spec->gpio_dir |= mask; + spec->gpio_data |= mask; +} + +static void alc_write_gpio_data(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_data); +} + +static void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask, + bool on) +{ + struct alc_spec *spec = codec->spec; + unsigned int oldval = spec->gpio_data; + + if (on) + spec->gpio_data |= mask; + else + spec->gpio_data &= ~mask; + if (oldval != spec->gpio_data) + alc_write_gpio_data(codec); +} + +static void alc_write_gpio(struct hda_codec *codec) { - if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers))) + struct alc_spec *spec = codec->spec; + + if (!spec->gpio_mask) return; - spec->mixers[spec->num_mixers++] = mix; + + snd_hda_codec_write(codec, codec->core.afg, 0, + AC_VERB_SET_GPIO_MASK, spec->gpio_mask); + snd_hda_codec_write(codec, codec->core.afg, 0, + AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir); + if (spec->gpio_write_delay) + msleep(1); + alc_write_gpio_data(codec); } -/* - * GPIO setup tables, used in initialization - */ -/* Enable GPIO mask and set output */ -static const struct hda_verb alc_gpio1_init_verbs[] = { - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - { } -}; +static void alc_fixup_gpio(struct hda_codec *codec, int action, + unsigned int mask) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + alc_setup_gpio(codec, mask); +} -static const struct hda_verb alc_gpio2_init_verbs[] = { - {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, - { } -}; +static void alc_fixup_gpio1(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_gpio(codec, action, 0x01); +} -static const struct hda_verb alc_gpio3_init_verbs[] = { - {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x03}, - { } -}; +static void alc_fixup_gpio2(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_gpio(codec, action, 0x02); +} + +static void alc_fixup_gpio3(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_gpio(codec, action, 0x03); +} + +static void alc_fixup_gpio4(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_gpio(codec, action, 0x04); +} /* * Fix hardware PLL issue @@ -447,16 +492,8 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) { alc_fill_eapd_coef(codec); alc_auto_setup_eapd(codec, true); + alc_write_gpio(codec); switch (type) { - case ALC_INIT_GPIO1: - snd_hda_sequence_write(codec, alc_gpio1_init_verbs); - break; - case ALC_INIT_GPIO2: - snd_hda_sequence_write(codec, alc_gpio2_init_verbs); - break; - case ALC_INIT_GPIO3: - snd_hda_sequence_write(codec, alc_gpio3_init_verbs); - break; case ALC_INIT_DEFAULT: switch (codec->core.vendor_id) { case 0x10ec0260: @@ -656,20 +693,22 @@ do_sku: * 7~6 : Reserved */ tmp = (ass & 0x38) >> 3; /* external Amp control */ - switch (tmp) { - case 1: - spec->init_amp = ALC_INIT_GPIO1; - break; - case 3: - spec->init_amp = ALC_INIT_GPIO2; - break; - case 7: - spec->init_amp = ALC_INIT_GPIO3; - break; - case 5: - default: - spec->init_amp = ALC_INIT_DEFAULT; - break; + if (spec->init_amp == ALC_INIT_UNDEFINED) { + switch (tmp) { + case 1: + alc_setup_gpio(codec, 0x01); + break; + case 3: + alc_setup_gpio(codec, 0x02); + break; + case 7: + alc_setup_gpio(codec, 0x03); + break; + case 5: + default: + spec->init_amp = ALC_INIT_DEFAULT; + break; + } } /* is laptop or Desktop and enable the function "Mute internal speaker @@ -722,47 +761,14 @@ static void alc_fixup_inv_dmic(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; - int i, err; + int err; err = snd_hda_gen_build_controls(codec); if (err < 0) return err; - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - 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 - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); return 0; } @@ -973,8 +979,30 @@ static int alc_codec_rename_from_preset(struct hda_codec *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)) + +/* additional beep mixers; private_value will be overwritten */ +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), +}; + +/* set up and create beep controls */ +static int set_beep_amp(struct alc_spec *spec, hda_nid_t nid, + int idx, int dir) +{ + struct snd_kcontrol_new *knew; + unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); + int i; + + for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) { + knew = snd_hda_gen_add_kctl(&spec->gen, NULL, + &alc_beep_mixer[i]); + if (!knew) + return -ENOMEM; + knew->private_value = beep_amp; + } + return 0; +} static const struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1), @@ -999,7 +1027,7 @@ static inline int has_cdefine_beep(struct hda_codec *codec) return spec->cdefine.enable_pcbeep; } #else -#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#define set_beep_amp(spec, nid, idx, dir) 0 #define has_cdefine_beep(codec) 0 #endif @@ -1104,12 +1132,12 @@ static void alc880_fixup_vol_knob(struct hda_codec *codec, static const struct hda_fixup alc880_fixups[] = { [ALC880_FIXUP_GPIO1] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = alc_gpio1_init_verbs, + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio1, }, [ALC880_FIXUP_GPIO2] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = alc_gpio2_init_verbs, + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio2, }, [ALC880_FIXUP_MEDION_RIM] = { .type = HDA_FIXUP_VERBS, @@ -1501,8 +1529,11 @@ static int patch_alc880(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->gen.no_analog) - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + if (!spec->gen.no_analog) { + err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + if (err < 0) + goto error; + } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); @@ -1544,8 +1575,8 @@ enum { static void alc260_gpio1_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->gen.hp_jack_present); + + alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present); } static void alc260_fixup_gpio1_toggle(struct hda_codec *codec, @@ -1562,7 +1593,7 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec, spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ snd_hda_jack_detect_enable_callback(codec, 0x0f, snd_hda_gen_hp_automute); - snd_hda_add_verbs(codec, alc_gpio1_init_verbs); + alc_setup_gpio(codec, 0x01); } } @@ -1589,8 +1620,6 @@ static void alc260_fixup_kn1(struct hda_codec *codec, switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: snd_hda_apply_pincfgs(codec, pincfgs); - break; - case HDA_FIXUP_ACT_PROBE: spec->init_amp = ALC_INIT_NONE; break; } @@ -1600,7 +1629,7 @@ static void alc260_fixup_fsc_s7020(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action == HDA_FIXUP_ACT_PROBE) + if (action == HDA_FIXUP_ACT_PRE_PROBE) spec->init_amp = ALC_INIT_NONE; } @@ -1638,8 +1667,8 @@ static const struct hda_fixup alc260_fixups[] = { }, }, [ALC260_FIXUP_GPIO1] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = alc_gpio1_init_verbs, + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio1, }, [ALC260_FIXUP_GPIO1_TOGGLE] = { .type = HDA_FIXUP_FUNC, @@ -1751,8 +1780,11 @@ static int patch_alc260(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->gen.no_analog) - set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); + if (!spec->gen.no_analog) { + err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); + if (err < 0) + goto error; + } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); @@ -1824,47 +1856,14 @@ static void alc889_fixup_coef(struct hda_codec *codec, alc_update_coef_idx(codec, 7, 0, 0x2030); } -/* toggle speaker-output according to the hp-jack state */ -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->core.afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - - if (!muted) - gpiostate |= (1 << pin); - else - gpiostate &= ~(1 << pin); - - gpiomask = snd_hda_codec_read(codec, codec->core.afg, 0, - AC_VERB_GET_GPIO_MASK, 0); - gpiomask |= (1 << pin); - - gpiodir = snd_hda_codec_read(codec, codec->core.afg, 0, - AC_VERB_GET_GPIO_DIRECTION, 0); - gpiodir |= (1 << pin); - - - snd_hda_codec_write(codec, codec->core.afg, 0, - AC_VERB_SET_GPIO_MASK, gpiomask); - snd_hda_codec_write(codec, codec->core.afg, 0, - AC_VERB_SET_GPIO_DIRECTION, gpiodir); - - msleep(1); - - snd_hda_codec_write(codec, codec->core.afg, 0, - AC_VERB_SET_GPIO_DATA, gpiostate); -} - /* set up GPIO at initialization */ static void alc885_fixup_macpro_gpio(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - if (action != HDA_FIXUP_ACT_INIT) - return; - alc882_gpio_mute(codec, 0, 0); - alc882_gpio_mute(codec, 1, 0); + struct alc_spec *spec = codec->spec; + + spec->gpio_write_delay = true; + alc_fixup_gpio3(codec, fix, action); } /* Fix the connection of some pins for ALC889: @@ -2143,20 +2142,20 @@ static const struct hda_fixup alc882_fixups[] = { } }, [ALC882_FIXUP_GPIO1] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = alc_gpio1_init_verbs, + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio1, }, [ALC882_FIXUP_GPIO2] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = alc_gpio2_init_verbs, + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio2, }, [ALC882_FIXUP_GPIO3] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = alc_gpio3_init_verbs, + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio3, }, [ALC882_FIXUP_ASUS_W2JC] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = alc_gpio1_init_verbs, + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio1, .chained = true, .chain_id = ALC882_FIXUP_EAPD, }, @@ -2375,12 +2374,37 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { }; static const struct hda_model_fixup alc882_fixup_models[] = { + {.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"}, + {.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"}, + {.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"}, + {.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"}, + {.id = ALC889_FIXUP_CD, .name = "cd"}, + {.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"}, + {.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"}, + {.id = ALC888_FIXUP_EEE1601, .name = "eee1601"}, + {.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"}, + {.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"}, + {.id = ALC882_FIXUP_GPIO1, .name = "gpio1"}, + {.id = ALC882_FIXUP_GPIO2, .name = "gpio2"}, + {.id = ALC882_FIXUP_GPIO3, .name = "gpio3"}, + {.id = ALC889_FIXUP_COEF, .name = "alc889-coef"}, + {.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"}, {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"}, {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"}, {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, + {.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"}, + {.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"}, + {.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"}, + {.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"}, + {.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"}, + {.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"}, + {.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"}, + {.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"}, {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"}, {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"}, + {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"}, {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"}, + {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"}, {} }; @@ -2434,8 +2458,11 @@ static int patch_alc882(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->gen.no_analog && spec->gen.beep_nid) - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + if (!spec->gen.no_analog && spec->gen.beep_nid) { + err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + if (err < 0) + goto error; + } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); @@ -2555,6 +2582,14 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = { static const struct hda_model_fixup alc262_fixup_models[] = { {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"}, + {.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"}, + {.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"}, + {.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"}, + {.id = ALC262_FIXUP_TYAN, .name = "tyan"}, + {.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"}, + {.id = ALC262_FIXUP_BENQ, .name = "benq"}, + {.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"}, + {.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"}, {} }; @@ -2596,8 +2631,11 @@ static int patch_alc262(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->gen.no_analog && spec->gen.beep_nid) - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + if (!spec->gen.no_analog && spec->gen.beep_nid) { + err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + if (err < 0) + goto error; + } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); @@ -2643,7 +2681,6 @@ static const struct snd_kcontrol_new alc268_beep_mixer[] = { .put = alc268_beep_switch_put, .private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT) }, - { } }; /* set PCBEEP vol = 0, mute connections */ @@ -2684,6 +2721,7 @@ static const struct hda_fixup alc268_fixups[] = { static const struct hda_model_fixup alc268_fixup_models[] = { {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"}, {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"}, + {.id = ALC268_FIXUP_SPDIF, .name = "spdif"}, {} }; @@ -2711,7 +2749,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) static int patch_alc268(struct hda_codec *codec) { struct alc_spec *spec; - int err; + int i, err; /* ALC268 has no aa-loopback mixer */ err = alc_alloc_spec(codec, 0); @@ -2733,7 +2771,13 @@ static int patch_alc268(struct hda_codec *codec) if (err > 0 && !spec->gen.no_analog && spec->gen.autocfg.speaker_pins[0] != 0x1d) { - add_mixer(spec, alc268_beep_mixer); + for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) { + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, + &alc268_beep_mixer[i])) { + err = -ENOMEM; + goto error; + } + } snd_hda_add_verbs(codec, alc268_beep_init_verbs); if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) /* override the amp caps for beep generator */ @@ -3452,9 +3496,8 @@ static int alc269_resume(struct hda_codec *codec) * suspend, and won't restore the data after resume, so we restore it * in the driver. */ - if (spec->gpio_led) - snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, - spec->gpio_led); + if (spec->gpio_data) + alc_write_gpio_data(codec); if (spec->has_alc5505_dsp) alc5505_dsp_resume(codec); @@ -3694,18 +3737,10 @@ static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask, bool enabled) { struct alc_spec *spec = codec->spec; - unsigned int oldval = spec->gpio_led; if (spec->mute_led_polarity) enabled = !enabled; - - if (enabled) - spec->gpio_led &= ~mask; - else - spec->gpio_led |= mask; - if (spec->gpio_led != oldval) - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->gpio_led); + alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */ } /* turn on/off mute LED via GPIO per vmaster hook */ @@ -3718,104 +3753,79 @@ static void alc_fixup_gpio_mute_hook(void *private_data, int enabled) } /* turn on/off mic-mute LED via GPIO per capture hook */ -static void alc_fixup_gpio_mic_mute_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc_gpio_micmute_update(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - if (ucontrol) - alc_update_gpio_led(codec, spec->gpio_mic_led_mask, - ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]); + alc_update_gpio_led(codec, spec->gpio_mic_led_mask, + spec->gen.micmute_led.led_value); } -static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, - const struct hda_fixup *fix, int action) +/* setup mute and mic-mute GPIO bits, add hooks appropriately */ +static void alc_fixup_hp_gpio_led(struct hda_codec *codec, + int action, + unsigned int mute_mask, + unsigned int micmute_mask) { struct alc_spec *spec = codec->spec; - static const struct hda_verb gpio_init[] = { - { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 }, - { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 }, - {} - }; - if (action == HDA_FIXUP_ACT_PRE_PROBE) { + alc_fixup_gpio(codec, action, mute_mask | micmute_mask); + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + if (mute_mask) { + spec->gpio_mute_led_mask = mute_mask; spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; - spec->gpio_led = 0; - spec->mute_led_polarity = 0; - spec->gpio_mute_led_mask = 0x08; - spec->gpio_mic_led_mask = 0x10; - snd_hda_add_verbs(codec, gpio_init); + } + if (micmute_mask) { + spec->gpio_mic_led_mask = micmute_mask; + snd_hda_gen_add_micmute_led(codec, alc_gpio_micmute_update); } } -static void alc286_fixup_hp_gpio_led(struct hda_codec *codec, +static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - struct alc_spec *spec = codec->spec; - static const struct hda_verb gpio_init[] = { - { 0x01, AC_VERB_SET_GPIO_MASK, 0x22 }, - { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x22 }, - {} - }; + alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10); +} - if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; - spec->gpio_led = 0; - spec->mute_led_polarity = 0; - spec->gpio_mute_led_mask = 0x02; - spec->gpio_mic_led_mask = 0x20; - snd_hda_add_verbs(codec, gpio_init); - } +static void alc286_fixup_hp_gpio_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_hp_gpio_led(codec, action, 0x02, 0x20); } /* turn on/off mic-mute LED per capture hook */ -static void alc269_fixup_hp_cap_mic_mute_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc_cap_micmute_update(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int pinval, enable, disable; + unsigned int pinval; + if (!spec->cap_mute_led_nid) + return; pinval = snd_hda_codec_get_pin_target(codec, spec->cap_mute_led_nid); pinval &= ~AC_PINCTL_VREFEN; - enable = pinval | AC_PINCTL_VREF_80; - disable = pinval | AC_PINCTL_VREF_HIZ; - - if (!ucontrol) - return; - - if (ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]) - pinval = disable; + if (spec->gen.micmute_led.led_value) + pinval |= AC_PINCTL_VREF_80; else - pinval = enable; - - if (spec->cap_mute_led_nid) - snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval); + pinval |= AC_PINCTL_VREF_HIZ; + snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval); } static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - static const struct hda_verb gpio_init[] = { - { 0x01, AC_VERB_SET_GPIO_MASK, 0x08 }, - { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x08 }, - {} - }; + alc_fixup_hp_gpio_led(codec, action, 0x08, 0); if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; - spec->gpio_led = 0; - spec->mute_led_polarity = 0; - spec->gpio_mute_led_mask = 0x08; + /* Like hp_gpio_mic1_led, but also needs GPIO4 low to + * enable headphone amp + */ + spec->gpio_mask |= 0x10; + spec->gpio_dir |= 0x10; spec->cap_mute_led_nid = 0x18; - snd_hda_add_verbs(codec, gpio_init); + snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update); codec->power_filter = led_power_filter; } } @@ -3823,22 +3833,12 @@ static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec, static void alc280_fixup_hp_gpio4(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - /* Like hp_gpio_mic1_led, but also needs GPIO4 low to enable headphone amp */ struct alc_spec *spec = codec->spec; - static const struct hda_verb gpio_init[] = { - { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 }, - { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 }, - {} - }; + alc_fixup_hp_gpio_led(codec, action, 0x08, 0); if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; - spec->gpio_led = 0; - spec->mute_led_polarity = 0; - spec->gpio_mute_led_mask = 0x08; spec->cap_mute_led_nid = 0x18; - snd_hda_add_verbs(codec, gpio_init); + snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update); codec->power_filter = led_power_filter; } } @@ -3888,38 +3888,29 @@ static int alc_register_micmute_input_device(struct hda_codec *codec) return 0; } +/* GPIO1 = set according to SKU external amp + * GPIO2 = mic mute hotkey + * GPIO3 = mute LED + * GPIO4 = mic mute LED + */ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - /* GPIO1 = set according to SKU external amp - GPIO2 = mic mute hotkey - GPIO3 = mute LED - GPIO4 = mic mute LED */ - static const struct hda_verb gpio_init[] = { - { 0x01, AC_VERB_SET_GPIO_MASK, 0x1e }, - { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a }, - { 0x01, AC_VERB_SET_GPIO_DATA, 0x02 }, - {} - }; - struct alc_spec *spec = codec->spec; + alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10); if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->init_amp = ALC_INIT_DEFAULT; if (alc_register_micmute_input_device(codec) != 0) return; - snd_hda_add_verbs(codec, gpio_init); + spec->gpio_mask |= 0x06; + spec->gpio_dir |= 0x02; + spec->gpio_data |= 0x02; snd_hda_codec_write_cache(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04); snd_hda_jack_detect_enable_callback(codec, codec->core.afg, gpio2_mic_hotkey_event); - - spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; - spec->gpio_led = 0; - spec->mute_led_polarity = 0; - spec->gpio_mute_led_mask = 0x08; - spec->gpio_mic_led_mask = 0x10; return; } @@ -3927,40 +3918,28 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, return; switch (action) { - case HDA_FIXUP_ACT_PROBE: - spec->init_amp = ALC_INIT_DEFAULT; - break; case HDA_FIXUP_ACT_FREE: input_unregister_device(spec->kb_dev); spec->kb_dev = NULL; } } +/* Line2 = mic mute hotkey + * GPIO2 = mic mute LED + */ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - /* Line2 = mic mute hotkey - GPIO2 = mic mute LED */ - static const struct hda_verb gpio_init[] = { - { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 }, - { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 }, - {} - }; - struct alc_spec *spec = codec->spec; + alc_fixup_hp_gpio_led(codec, action, 0, 0x04); if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->init_amp = ALC_INIT_DEFAULT; if (alc_register_micmute_input_device(codec) != 0) return; - snd_hda_add_verbs(codec, gpio_init); snd_hda_jack_detect_enable_callback(codec, 0x1b, gpio2_mic_hotkey_event); - - spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; - spec->gpio_led = 0; - spec->mute_led_polarity = 0; - spec->gpio_mic_led_mask = 0x04; return; } @@ -3968,9 +3947,6 @@ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec, return; switch (action) { - case HDA_FIXUP_ACT_PROBE: - spec->init_amp = ALC_INIT_DEFAULT; - break; case HDA_FIXUP_ACT_FREE: input_unregister_device(spec->kb_dev); spec->kb_dev = NULL; @@ -3986,14 +3962,10 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, { struct alc_spec *spec = codec->spec; + alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1a); if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; - spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; - spec->mute_led_polarity = 0; - spec->mute_led_nid = 0x1a; spec->cap_mute_led_nid = 0x18; - spec->gen.vmaster_mute_enum = 1; - codec->power_filter = led_power_filter; + snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update); } } @@ -4841,6 +4813,7 @@ static void alc_probe_headset_mode(struct hda_codec *codec) spec->headphone_mic_pin = cfg->inputs[i].pin; } + WARN_ON(spec->gen.cap_sync_hook); spec->gen.cap_sync_hook = alc_update_headset_mode_hook; spec->gen.automute_hook = alc_update_headset_mode; spec->gen.hp_automute_hook = alc_update_headset_jack_cb; @@ -4932,13 +4905,10 @@ static void alc288_update_headset_jack_cb(struct hda_codec *codec, struct hda_jack_callback *jack) { struct alc_spec *spec = codec->spec; - int present; alc_update_headset_jack_cb(codec, jack); /* Headset Mic enable or disable, only for Dell Dino */ - present = spec->gen.hp_jack_present ? 0x40 : 0; - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - present); + alc_update_gpio_data(codec, 0x40, spec->gen.hp_jack_present); } static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec, @@ -4947,6 +4917,9 @@ static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec, alc_fixup_headset_mode(codec, fix, action); if (action == HDA_FIXUP_ACT_PROBE) { struct alc_spec *spec = codec->spec; + /* toggled via hp_automute_hook */ + spec->gpio_mask |= 0x40; + spec->gpio_dir |= 0x40; spec->gen.hp_automute_hook = alc288_update_headset_jack_cb; } } @@ -4967,7 +4940,7 @@ static void alc_no_shutup(struct hda_codec *codec) static void alc_fixup_no_shutup(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - if (action == HDA_FIXUP_ACT_PROBE) { + if (action == HDA_FIXUP_ACT_PRE_PROBE) { struct alc_spec *spec = codec->spec; spec->shutup = alc_no_shutup; } @@ -4995,7 +4968,6 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec, struct alc_spec *spec = codec->spec; if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->shutup = alc_no_shutup; /* reduce click noise */ spec->reboot_notify = alc_d3_at_reboot; /* reduce noise */ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; codec->power_save_node = 0; /* avoid click noises */ @@ -5050,10 +5022,9 @@ static void alc_fixup_dell_xps13(struct hda_codec *codec, * it causes a click noise at start up */ snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ); + spec->shutup = alc_shutup_dell_xps13; break; case HDA_FIXUP_ACT_PROBE: - spec->shutup = alc_shutup_dell_xps13; - /* Make the internal mic the default input source. */ for (i = 0; i < imux->num_items; i++) { if (spec->gen.imux_pins[i] == 0x12) { @@ -5230,13 +5201,6 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - /* TX300 needs to set up GPIO2 for the speaker amp */ - static const struct hda_verb gpio2_verbs[] = { - { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 }, - { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 }, - { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 }, - {} - }; static const struct hda_pintbl dock_pins[] = { { 0x1b, 0x21114000 }, /* dock speaker pin */ {} @@ -5244,13 +5208,18 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec, switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: - snd_hda_add_verbs(codec, gpio2_verbs); + spec->init_amp = ALC_INIT_DEFAULT; + /* TX300 needs to set up GPIO2 for the speaker amp */ + alc_setup_gpio(codec, 0x04); snd_hda_apply_pincfgs(codec, dock_pins); spec->gen.auto_mute_via_amp = 1; spec->gen.automute_hook = asus_tx300_automute; snd_hda_jack_detect_enable_callback(codec, 0x1b, snd_hda_gen_hp_automute); break; + case HDA_FIXUP_ACT_PROBE: + spec->init_amp = ALC_INIT_DEFAULT; + break; case HDA_FIXUP_ACT_BUILD: /* this is a bit tricky; give more sane names for the main * (tablet) speaker and the dock speaker, respectively @@ -5324,30 +5293,26 @@ static void alc280_fixup_hp_9480m(struct hda_codec *codec, int action) { struct alc_spec *spec = codec->spec; - static const struct hda_verb gpio_init[] = { - { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 }, - { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 }, - {} - }; + alc_fixup_hp_gpio_led(codec, action, 0x08, 0); if (action == HDA_FIXUP_ACT_PRE_PROBE) { - /* Set the hooks to turn the headphone amp on/off - * as needed - */ - spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; + /* amp at GPIO4; toggled via alc280_hp_gpio4_automute_hook() */ + spec->gpio_mask |= 0x10; + spec->gpio_dir |= 0x10; spec->gen.hp_automute_hook = alc280_hp_gpio4_automute_hook; + } +} - /* The GPIOs are currently off */ - spec->gpio_led = 0; - - /* GPIO3 is connected to the output mute LED, - * high is on, low is off - */ - spec->mute_led_polarity = 0; - spec->gpio_mute_led_mask = 0x08; +static void alc275_fixup_gpio4_off(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; - /* Initialize GPIO configuration */ - snd_hda_add_verbs(codec, gpio_init); + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gpio_mask |= 0x04; + spec->gpio_dir |= 0x04; + /* set data bit low */ } } @@ -5394,6 +5359,13 @@ static void alc274_fixup_bind_dacs(struct hda_codec *codec, /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" +static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_no_shutup(codec, fix, action); /* reduce click noise */ + hda_fixup_thinkpad_acpi(codec, fix, action); +} + /* for dell wmi mic mute led */ #include "dell_wmi_helper.c" @@ -5484,7 +5456,6 @@ enum { ALC280_FIXUP_HP_9480M, ALC288_FIXUP_DELL_HEADSET_MODE, ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC288_FIXUP_DELL_XPS_13_GPIO6, ALC288_FIXUP_DELL_XPS_13, ALC288_FIXUP_DISABLE_AAMIX, ALC292_FIXUP_DELL_E7X, @@ -5532,13 +5503,8 @@ static const struct hda_fixup alc269_fixups[] = { } }, [ALC275_FIXUP_SONY_VAIO_GPIO2] = { - .type = HDA_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}, - { } - }, + .type = HDA_FIXUP_FUNC, + .v.func = alc275_fixup_gpio4_off, .chained = true, .chain_id = ALC269_FIXUP_SONY_VAIO }, @@ -5946,7 +5912,7 @@ static const struct hda_fixup alc269_fixups[] = { }, [ALC269_FIXUP_THINKPAD_ACPI] = { .type = HDA_FIXUP_FUNC, - .v.func = hda_fixup_thinkpad_acpi, + .v.func = alc_fixup_thinkpad_acpi, .chained = true, .chain_id = ALC269_FIXUP_SKU_IGNORE, }, @@ -6105,22 +6071,11 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC288_FIXUP_DELL_HEADSET_MODE }, - [ALC288_FIXUP_DELL_XPS_13_GPIO6] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x01, AC_VERB_SET_GPIO_MASK, 0x40}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x40}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - { } - }, - .chained = true, - .chain_id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE - }, [ALC288_FIXUP_DISABLE_AAMIX] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_disable_aamix, .chained = true, - .chain_id = ALC288_FIXUP_DELL_XPS_13_GPIO6 + .chain_id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE }, [ALC288_FIXUP_DELL_XPS_13] = { .type = HDA_FIXUP_FUNC, @@ -6283,14 +6238,9 @@ static const struct hda_fixup alc269_fixups[] = { .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE }, [ALC256_FIXUP_ASUS_AIO_GPIO2] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* Set up GPIO2 for the speaker amp */ - { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 }, - { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 }, - { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 }, - {} - }, + .type = HDA_FIXUP_FUNC, + /* Set up GPIO2 for the speaker amp */ + .v.func = alc_fixup_gpio4, }, [ALC233_FIXUP_ASUS_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, @@ -6704,13 +6654,95 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED, .name = "hp-dock-gpio-mic1-led"}, {.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"}, {.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"}, + {.id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, .name = "dell-headset3"}, + {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, .name = "dell-headset4"}, {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"}, {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"}, {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"}, {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, {.id = ALC292_FIXUP_TPT460, .name = "tpt460"}, + {.id = ALC298_FIXUP_TPT470_DOCK, .name = "tpt470-dock"}, {.id = ALC233_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"}, {.id = ALC700_FIXUP_INTEL_REFERENCE, .name = "alc700-ref"}, + {.id = ALC269_FIXUP_SONY_VAIO, .name = "vaio"}, + {.id = ALC269_FIXUP_DELL_M101Z, .name = "dell-m101z"}, + {.id = ALC269_FIXUP_ASUS_G73JW, .name = "asus-g73jw"}, + {.id = ALC269_FIXUP_LENOVO_EAPD, .name = "lenovo-eapd"}, + {.id = ALC275_FIXUP_SONY_HWEQ, .name = "sony-hweq"}, + {.id = ALC269_FIXUP_PCM_44K, .name = "pcm44k"}, + {.id = ALC269_FIXUP_LIFEBOOK, .name = "lifebook"}, + {.id = ALC269_FIXUP_LIFEBOOK_EXTMIC, .name = "lifebook-extmic"}, + {.id = ALC269_FIXUP_LIFEBOOK_HP_PIN, .name = "lifebook-hp-pin"}, + {.id = ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC, .name = "lifebook-u7x7"}, + {.id = ALC269VB_FIXUP_AMIC, .name = "alc269vb-amic"}, + {.id = ALC269VB_FIXUP_DMIC, .name = "alc269vb-dmic"}, + {.id = ALC269_FIXUP_HP_MUTE_LED_MIC1, .name = "hp-mute-led-mic1"}, + {.id = ALC269_FIXUP_HP_MUTE_LED_MIC2, .name = "hp-mute-led-mic2"}, + {.id = ALC269_FIXUP_HP_MUTE_LED_MIC3, .name = "hp-mute-led-mic3"}, + {.id = ALC269_FIXUP_HP_GPIO_MIC1_LED, .name = "hp-gpio-mic1"}, + {.id = ALC269_FIXUP_HP_LINE1_MIC1_LED, .name = "hp-line1-mic1"}, + {.id = ALC269_FIXUP_NO_SHUTUP, .name = "noshutup"}, + {.id = ALC286_FIXUP_SONY_MIC_NO_PRESENCE, .name = "sony-nomic"}, + {.id = ALC269_FIXUP_ASPIRE_HEADSET_MIC, .name = "aspire-headset-mic"}, + {.id = ALC269_FIXUP_ASUS_X101, .name = "asus-x101"}, + {.id = ALC271_FIXUP_HP_GATE_MIC_JACK, .name = "acer-ao7xx"}, + {.id = ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572, .name = "acer-aspire-e1"}, + {.id = ALC269_FIXUP_ACER_AC700, .name = "acer-ac700"}, + {.id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST, .name = "limit-mic-boost"}, + {.id = ALC269VB_FIXUP_ASUS_ZENBOOK, .name = "asus-zenbook"}, + {.id = ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A, .name = "asus-zenbook-ux31a"}, + {.id = ALC269VB_FIXUP_ORDISSIMO_EVE2, .name = "ordissimo"}, + {.id = ALC282_FIXUP_ASUS_TX300, .name = "asus-tx300"}, + {.id = ALC283_FIXUP_INT_MIC, .name = "alc283-int-mic"}, + {.id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK, .name = "mono-speakers"}, + {.id = ALC290_FIXUP_SUBWOOFER_HSJACK, .name = "alc290-subwoofer"}, + {.id = ALC269_FIXUP_THINKPAD_ACPI, .name = "thinkpad"}, + {.id = ALC269_FIXUP_DMIC_THINKPAD_ACPI, .name = "dmic-thinkpad"}, + {.id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE, .name = "alc255-acer"}, + {.id = ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc255-asus"}, + {.id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc255-dell1"}, + {.id = ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "alc255-dell2"}, + {.id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc293-dell1"}, + {.id = ALC283_FIXUP_HEADSET_MIC, .name = "alc283-headset"}, + {.id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, .name = "alc255-dell-mute"}, + {.id = ALC282_FIXUP_ASPIRE_V5_PINS, .name = "aspire-v5"}, + {.id = ALC280_FIXUP_HP_GPIO4, .name = "hp-gpio4"}, + {.id = ALC286_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"}, + {.id = ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, .name = "hp-gpio2-hotkey"}, + {.id = ALC280_FIXUP_HP_DOCK_PINS, .name = "hp-dock-pins"}, + {.id = ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED, .name = "hp-dock-gpio-mic"}, + {.id = ALC280_FIXUP_HP_9480M, .name = "hp-9480m"}, + {.id = ALC288_FIXUP_DELL_HEADSET_MODE, .name = "alc288-dell-headset"}, + {.id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc288-dell1"}, + {.id = ALC288_FIXUP_DELL_XPS_13, .name = "alc288-dell-xps13"}, + {.id = ALC292_FIXUP_DELL_E7X, .name = "dell-e7x"}, + {.id = ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK, .name = "alc293-dell"}, + {.id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc298-dell1"}, + {.id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE, .name = "alc298-dell-aio"}, + {.id = ALC275_FIXUP_DELL_XPS, .name = "alc275-dell-xps"}, + {.id = ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, .name = "alc256-dell-xps13"}, + {.id = ALC293_FIXUP_LENOVO_SPK_NOISE, .name = "lenovo-spk-noise"}, + {.id = ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, .name = "lenovo-hotkey"}, + {.id = ALC255_FIXUP_DELL_SPK_NOISE, .name = "dell-spk-noise"}, + {.id = ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc255-dell1"}, + {.id = ALC295_FIXUP_DISABLE_DAC3, .name = "alc295-disable-dac3"}, + {.id = ALC280_FIXUP_HP_HEADSET_MIC, .name = "alc280-hp-headset"}, + {.id = ALC221_FIXUP_HP_FRONT_MIC, .name = "alc221-hp-mic"}, + {.id = ALC298_FIXUP_SPK_VOLUME, .name = "alc298-spk-volume"}, + {.id = ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, .name = "dell-inspiron-7559"}, + {.id = ALC269_FIXUP_ATIV_BOOK_8, .name = "ativ-book"}, + {.id = ALC221_FIXUP_HP_MIC_NO_PRESENCE, .name = "alc221-hp-mic"}, + {.id = ALC256_FIXUP_ASUS_HEADSET_MODE, .name = "alc256-asus-headset"}, + {.id = ALC256_FIXUP_ASUS_MIC, .name = "alc256-asus-mic"}, + {.id = ALC256_FIXUP_ASUS_AIO_GPIO2, .name = "alc256-asus-aio"}, + {.id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc233-asus"}, + {.id = ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE, .name = "alc233-eapd"}, + {.id = ALC294_FIXUP_LENOVO_MIC_LOCATION, .name = "alc294-lenovo-mic"}, + {.id = ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE, .name = "alc225-wyse"}, + {.id = ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, .name = "alc274-dell-aio"}, + {.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"}, + {.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"}, + {.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"}, {} }; #define ALC225_STANDARD_PINS \ @@ -6963,7 +6995,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60130}, {0x19, 0x03a11020}, {0x21, 0x0321101f}), - SND_HDA_PIN_QUIRK(0x10ec0288, 0x1028, "Dell", ALC288_FIXUP_DELL_XPS_13_GPIO6, + SND_HDA_PIN_QUIRK(0x10ec0288, 0x1028, "Dell", ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60120}, {0x14, 0x90170110}, {0x21, 0x0321101f}), @@ -7120,18 +7152,6 @@ static int patch_alc269(struct hda_codec *codec) spec->shutup = alc_default_shutup; spec->init_hook = alc_default_init; - snd_hda_pick_fixup(codec, alc269_fixup_models, - alc269_fixup_tbl, alc269_fixups); - snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups); - snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl, - alc269_fixups); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - - alc_auto_parse_customize_define(codec); - - if (has_cdefine_beep(codec)) - spec->gen.beep_nid = 0x01; - switch (codec->core.vendor_id) { case 0x10ec0269: spec->codec_variant = ALC269_TYPE_ALC269VA; @@ -7251,13 +7271,28 @@ static int patch_alc269(struct hda_codec *codec) spec->init_hook = alc5505_dsp_init; } + snd_hda_pick_fixup(codec, alc269_fixup_models, + alc269_fixup_tbl, alc269_fixups); + snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups); + snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl, + alc269_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + alc_auto_parse_customize_define(codec); + + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x01; + /* automatic parse from the BIOS config */ err = alc269_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->gen.no_analog && spec->gen.beep_nid && spec->gen.mixer_nid) - set_beep_amp(spec, spec->gen.mixer_nid, 0x04, HDA_INPUT); + if (!spec->gen.no_analog && spec->gen.beep_nid && spec->gen.mixer_nid) { + err = set_beep_amp(spec, spec->gen.mixer_nid, 0x04, HDA_INPUT); + if (err < 0) + goto error; + } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); @@ -7386,8 +7421,11 @@ static int patch_alc861(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->gen.no_analog) - set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); + if (!spec->gen.no_analog) { + err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); + if (err < 0) + goto error; + } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); @@ -7427,16 +7465,21 @@ static void alc861vd_fixup_dallas(struct hda_codec *codec, } } +/* reset GPIO1 */ +static void alc660vd_fixup_asus_gpio1(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->gpio_mask |= 0x02; + alc_fixup_gpio(codec, action, 0x01); +} + static const struct hda_fixup alc861vd_fixups[] = { [ALC660VD_FIX_ASUS_GPIO1] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* reset GPIO1 */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - { } - } + .type = HDA_FIXUP_FUNC, + .v.func = alc660vd_fixup_asus_gpio1, }, [ALC861VD_FIX_DALLAS] = { .type = HDA_FIXUP_FUNC, @@ -7475,8 +7518,11 @@ static int patch_alc861vd(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->gen.no_analog) - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + if (!spec->gen.no_analog) { + err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + if (err < 0) + goto error; + } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); @@ -7557,7 +7603,7 @@ static unsigned int gpio_led_power_filter(struct hda_codec *codec, unsigned int power_state) { struct alc_spec *spec = codec->spec; - if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_led) + if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data) return AC_PWRST_D0; return power_state; } @@ -7566,18 +7612,10 @@ static void alc662_fixup_led_gpio1(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - static const struct hda_verb gpio_init[] = { - { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 }, - { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 }, - {} - }; + alc_fixup_hp_gpio_led(codec, action, 0x01, 0); if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gpio_led = 0; spec->mute_led_polarity = 1; - spec->gpio_mute_led_mask = 0x01; - snd_hda_add_verbs(codec, gpio_init); codec->power_filter = gpio_led_power_filter; } } @@ -8090,7 +8128,10 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { }; static const struct hda_model_fixup alc662_fixup_models[] = { + {.id = ALC662_FIXUP_ASPIRE, .name = "aspire"}, + {.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"}, {.id = ALC272_FIXUP_MARIO, .name = "mario"}, + {.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"}, {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"}, {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"}, {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"}, @@ -8099,8 +8140,23 @@ static const struct hda_model_fixup alc662_fixup_models[] = { {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"}, {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"}, {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"}, + {.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"}, {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"}, + {.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"}, {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"}, + {.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"}, + {.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"}, + {.id = ALC662_FIXUP_BASS_16, .name = "bass16"}, + {.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"}, + {.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"}, + {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"}, + {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"}, + {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"}, + {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"}, + {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"}, + {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"}, + {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"}, + {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"}, {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"}, {} }; @@ -8194,18 +8250,20 @@ static int patch_alc662(struct hda_codec *codec) if (!spec->gen.no_analog && spec->gen.beep_nid) { switch (codec->core.vendor_id) { case 0x10ec0662: - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); break; case 0x10ec0272: case 0x10ec0663: case 0x10ec0665: case 0x10ec0668: - set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); + err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); break; case 0x10ec0273: - set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT); + err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT); break; } + if (err < 0) + goto error; } snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 63d15b545b33..046705b4691a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -332,33 +332,15 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, } /* hook for controlling mic-mute LED GPIO */ -static void stac_capture_led_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void stac_capture_led_update(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - unsigned int mask; - bool cur_mute, prev_mute; - if (!kcontrol || !ucontrol) - return; - - mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - prev_mute = !spec->mic_enabled; - if (ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]) - spec->mic_enabled |= mask; + if (spec->gen.micmute_led.led_value) + spec->gpio_data |= spec->mic_mute_led_gpio; else - spec->mic_enabled &= ~mask; - cur_mute = !spec->mic_enabled; - if (cur_mute != prev_mute) { - if (cur_mute) - spec->gpio_data |= spec->mic_mute_led_gpio; - else - spec->gpio_data &= ~spec->mic_mute_led_gpio; - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data); - } + spec->gpio_data &= ~spec->mic_mute_led_gpio; + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); } static int stac_vrefout_set(struct hda_codec *codec, @@ -4656,8 +4638,7 @@ static void stac_setup_gpio(struct hda_codec *codec) spec->gpio_dir |= spec->mic_mute_led_gpio; spec->mic_enabled = 0; spec->gpio_data |= spec->mic_mute_led_gpio; - - spec->gen.cap_sync_hook = stac_capture_led_hook; + snd_hda_gen_add_micmute_led(codec, stac_capture_led_update); } } diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index fc30d1e8aa76..6b9617aee0e6 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -90,13 +90,6 @@ enum VIA_HDA_CODEC { struct via_spec { struct hda_gen_spec gen; - /* codec parameterization */ - const struct snd_kcontrol_new *mixers[6]; - unsigned int num_mixers; - - const struct hda_verb *init_verbs[5]; - unsigned int num_iverbs; - /* HP mode source */ unsigned int dmic_enabled; enum VIA_HDA_CODEC codec_type; @@ -107,8 +100,6 @@ struct via_spec { /* work to check hp jack state */ int hp_work_active; int vt1708_jack_detect; - - unsigned int beep_amp; }; static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec); @@ -262,69 +253,51 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new via_pin_power_ctl_enum[] = { - { +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, - }, - {} /* terminator */ }; #ifdef CONFIG_SND_HDA_INPUT_BEEP -static inline void set_beep_amp(struct via_spec *spec, hda_nid_t nid, - int idx, int dir) -{ - spec->gen.beep_nid = nid; - spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); -} - /* additional beep mixers; the actual parameters are overwritten at build */ -static const struct snd_kcontrol_new cxt_beep_mixer[] = { +static const struct snd_kcontrol_new via_beep_mixer[] = { HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), - { } /* end */ }; -/* create beep controls if needed */ -static int add_beep_ctls(struct hda_codec *codec) +static int set_beep_amp(struct via_spec *spec, hda_nid_t nid, + int idx, int dir) { - struct via_spec *spec = codec->spec; - int err; + struct snd_kcontrol_new *knew; + unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); + int i; - if (spec->beep_amp) { - const struct snd_kcontrol_new *knew; - for (knew = cxt_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; - } + spec->gen.beep_nid = nid; + for (i = 0; i < ARRAY_SIZE(via_beep_mixer); i++) { + knew = snd_hda_gen_add_kctl(&spec->gen, NULL, + &via_beep_mixer[i]); + if (!knew) + return -ENOMEM; + knew->private_value = beep_amp; } return 0; } -static void auto_parse_beep(struct hda_codec *codec) +static int auto_parse_beep(struct hda_codec *codec) { struct via_spec *spec = codec->spec; hda_nid_t nid; for_each_hda_codec_node(nid, codec) - if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) { - set_beep_amp(spec, nid, 0, HDA_OUTPUT); - break; - } + if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) + return set_beep_amp(spec, nid, 0, HDA_OUTPUT); + return 0; } #else -#define set_beep_amp(spec, nid, idx, dir) /* NOP */ -#define add_beep_ctls(codec) 0 -#define auto_parse_beep(codec) +#define auto_parse_beep(codec) 0 #endif /* check AA path's mute status */ @@ -403,30 +376,6 @@ static void analog_low_current_mode(struct hda_codec *codec) return __analog_low_current_mode(codec, false); } -static int via_build_controls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int err, i; - - err = snd_hda_gen_build_controls(codec); - if (err < 0) - return err; - - err = add_beep_ctls(codec); - if (err < 0) - return err; - - spec->mixers[spec->num_mixers++] = via_pin_power_ctl_enum; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - - return 0; -} - static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream, @@ -481,7 +430,7 @@ 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_controls = snd_hda_gen_build_controls, .build_pcms = snd_hda_gen_build_pcms, .init = via_init, .free = via_free, @@ -545,16 +494,13 @@ static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new vt1708_jack_detect_ctl[] = { - { +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, - }, - {} /* terminator */ }; static const struct badness_table via_main_out_badness = { @@ -586,12 +532,17 @@ static int via_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - auto_parse_beep(codec); - err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) return err; + err = auto_parse_beep(codec); + if (err < 0) + return err; + + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &via_pin_power_ctl_enum)) + return -ENOMEM; + /* disable widget PM at start for compatibility */ codec->power_save_node = 0; spec->gen.power_down_unused = 0; @@ -600,12 +551,6 @@ static int via_parse_auto_config(struct hda_codec *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]); - /* init power states */ __analog_low_current_mode(codec, true); @@ -623,7 +568,7 @@ static int vt1708_build_controls(struct hda_codec *codec) int err; int old_interval = codec->jackpoll_interval; codec->jackpoll_interval = msecs_to_jiffies(100); - err = via_build_controls(codec); + err = snd_hda_gen_build_controls(codec); codec->jackpoll_interval = old_interval; return err; } @@ -684,22 +629,29 @@ static int patch_vt1708(struct hda_codec *codec) vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID); + err = snd_hda_add_verbs(codec, vt1708_init_verbs); + if (err < 0) + goto error; + /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } + if (err < 0) + goto error; /* add jack detect on/off control */ - spec->mixers[spec->num_mixers++] = vt1708_jack_detect_ctl; - - spec->init_verbs[spec->num_iverbs++] = vt1708_init_verbs; + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl)) { + err = -ENOMEM; + goto error; + } /* clear jackpoll_interval again; it's set dynamically */ codec->jackpoll_interval = 0; return 0; + + error: + via_free(codec); + return err; } static int patch_vt1709(struct hda_codec *codec) @@ -715,12 +667,14 @@ static int patch_vt1709(struct hda_codec *codec) spec->gen.mixer_nid = 0x18; err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } + if (err < 0) + goto error; return 0; + + error: + via_free(codec); + return err; } static int patch_vt1708S(struct hda_codec *codec); @@ -741,12 +695,14 @@ static int patch_vt1708B(struct hda_codec *codec) /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } + if (err < 0) + goto error; return 0; + + error: + via_free(codec); + return err; } /* Patch for VT1708S */ @@ -791,16 +747,20 @@ static int patch_vt1708S(struct hda_codec *codec) if (codec->core.vendor_id == 0x11064397) snd_hda_codec_set_name(codec, "VT1705"); + err = snd_hda_add_verbs(codec, vt1708S_init_verbs); + if (err < 0) + goto error; + /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } - - spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs; + if (err < 0) + goto error; return 0; + + error: + via_free(codec); + return err; } /* Patch for VT1702 */ @@ -832,16 +792,20 @@ static int patch_vt1702(struct hda_codec *codec) (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) | (1 << AC_AMPCAP_MUTE_SHIFT)); + err = snd_hda_add_verbs(codec, vt1702_init_verbs); + if (err < 0) + goto error; + /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } - - spec->init_verbs[spec->num_iverbs++] = vt1702_init_verbs; + if (err < 0) + goto error; return 0; + + error: + via_free(codec); + return err; } /* Patch for VT1718S */ @@ -904,16 +868,20 @@ static int patch_vt1718S(struct hda_codec *codec) override_mic_boost(codec, 0x29, 0, 3, 40); add_secret_dac_path(codec); + err = snd_hda_add_verbs(codec, vt1718S_init_verbs); + if (err < 0) + goto error; + /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } - - spec->init_verbs[spec->num_iverbs++] = vt1718S_init_verbs; + if (err < 0) + goto error; return 0; + + error: + via_free(codec); + return err; } /* Patch for VT1716S */ @@ -955,9 +923,9 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = { - HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT), - { +static const struct snd_kcontrol_new vt1716s_dmic_mixer_vol = + HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT); +static const struct snd_kcontrol_new vt1716s_dmic_mixer_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Digital Mic Capture Switch", .subdevice = HDA_SUBDEV_NID_FLAG | 0x26, @@ -965,16 +933,12 @@ static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = { .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 snd_kcontrol_new vt1716S_mono_out_mixer = + HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT); static const struct hda_verb vt1716S_init_verbs[] = { /* Enable Boost Volume backdoor */ @@ -1000,19 +964,27 @@ static int patch_vt1716S(struct hda_codec *codec) override_mic_boost(codec, 0x1a, 0, 3, 40); override_mic_boost(codec, 0x1e, 0, 3, 40); + err = snd_hda_add_verbs(codec, vt1716S_init_verbs); + if (err < 0) + goto error; + /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } - - spec->init_verbs[spec->num_iverbs++] = vt1716S_init_verbs; + if (err < 0) + goto error; - spec->mixers[spec->num_mixers++] = vt1716s_dmic_mixer; - spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_vol) || + !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_sw) || + !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer)) { + err = -ENOMEM; + goto error; + } return 0; + + error: + via_free(codec); + return err; } /* for vt2002P */ @@ -1107,19 +1079,23 @@ static int patch_vt2002P(struct hda_codec *codec) snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } - if (spec->codec_type == VT1802) - spec->init_verbs[spec->num_iverbs++] = vt1802_init_verbs; + err = snd_hda_add_verbs(codec, vt1802_init_verbs); else - spec->init_verbs[spec->num_iverbs++] = vt2002P_init_verbs; + err = snd_hda_add_verbs(codec, vt2002P_init_verbs); + if (err < 0) + goto error; + + /* automatic parse from the BIOS config */ + err = via_parse_auto_config(codec); + if (err < 0) + goto error; return 0; + + error: + via_free(codec); + return err; } /* for vt1812 */ @@ -1148,16 +1124,20 @@ static int patch_vt1812(struct hda_codec *codec) override_mic_boost(codec, 0x29, 0, 3, 40); add_secret_dac_path(codec); + err = snd_hda_add_verbs(codec, vt1812_init_verbs); + if (err < 0) + goto error; + /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } - - spec->init_verbs[spec->num_iverbs++] = vt1812_init_verbs; + if (err < 0) + goto error; return 0; + + error: + via_free(codec); + return err; } /* patch for vt3476 */ @@ -1185,16 +1165,20 @@ static int patch_vt3476(struct hda_codec *codec) spec->gen.mixer_nid = 0x3f; add_secret_dac_path(codec); + err = snd_hda_add_verbs(codec, vt3476_init_verbs); + if (err < 0) + goto error; + /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } - - spec->init_verbs[spec->num_iverbs++] = vt3476_init_verbs; + if (err < 0) + goto error; return 0; + + error: + via_free(codec); + return err; } /* diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c index 65bb3ac6af4c..97f49b751e6e 100644 --- a/sound/pci/hda/thinkpad_helper.c +++ b/sound/pci/hda/thinkpad_helper.c @@ -27,17 +27,11 @@ static void update_tpacpi_mute_led(void *private_data, int enabled) led_set_func(TPACPI_LED_MUTE, !enabled); } -static void update_tpacpi_micmute_led(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void update_tpacpi_micmute(struct hda_codec *codec) { - if (!ucontrol || !led_set_func) - return; - if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) { - /* TODO: How do I verify if it's a mono or stereo here? */ - bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1]; - led_set_func(TPACPI_LED_MICMUTE, !val); - } + struct hda_gen_spec *spec = codec->spec; + + led_set_func(TPACPI_LED_MICMUTE, spec->micmute_led.led_value); } static void hda_fixup_thinkpad_acpi(struct hda_codec *codec, @@ -63,15 +57,10 @@ static void hda_fixup_thinkpad_acpi(struct hda_codec *codec, spec->vmaster_mute.hook = update_tpacpi_mute_led; removefunc = false; } - if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) { - if (spec->num_adc_nids > 1 && !spec->dyn_adc_switch) - codec_dbg(codec, - "Skipping micmute LED control due to several ADCs"); - else { - spec->cap_sync_hook = update_tpacpi_micmute_led; - removefunc = false; - } - } + if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0 && + snd_hda_gen_add_micmute_led(codec, + update_tpacpi_micmute) > 0) + removefunc = false; } if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) { diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index d7366ade5a25..c97b5528e4b8 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -314,26 +314,7 @@ static struct snd_kcontrol_new prodigy_hd2_controls[] = { /* --------------- */ -/* - * Logarithmic volume values for WM87*6 - * Computed as 20 * Log10(255 / x) - */ -static const unsigned char wm_vol[256] = { - 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, - 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, - 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, - 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 -}; - -#define WM_VOL_MAX (sizeof(wm_vol) - 1) +#define WM_VOL_MAX 255 #define WM_VOL_MUTE 0x8000 diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index f35d29f49ffe..15344d39a6cd 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -636,6 +636,7 @@ static void read_completed(struct urb *urb) struct device *dev; struct urb *out = NULL; int i, frame, len, send_it = 0, outframe = 0; + unsigned long flags; size_t offset = 0; if (urb->status || !info) @@ -672,10 +673,10 @@ static void read_completed(struct urb *urb) offset += len; if (len > 0) { - spin_lock(&cdev->spinlock); + spin_lock_irqsave(&cdev->spinlock, flags); fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]); read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]); - spin_unlock(&cdev->spinlock); + spin_unlock_irqrestore(&cdev->spinlock, flags); check_for_elapsed_periods(cdev, cdev->sub_playback); check_for_elapsed_periods(cdev, cdev->sub_capture); send_it = 1; diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index 750467fb95db..f47ba94e6f4a 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -367,12 +367,13 @@ static bool toneport_has_source_select(struct usb_line6_toneport *toneport) */ static void toneport_setup(struct usb_line6_toneport *toneport) { - int ticks; + u32 ticks; struct usb_line6 *line6 = &toneport->line6; struct usb_device *usbdev = line6->usbdev; /* sync time on device with host: */ - ticks = (int)get_seconds(); + /* note: 32-bit timestamps overflow in year 2106 */ + ticks = (u32)ktime_get_real_seconds(); line6_write_data(line6, 0x80c6, &ticks, 4); /* enable device: */ diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 2c1aaa3292bf..dcfc546d81b9 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -281,15 +281,16 @@ static void snd_usbmidi_out_urb_complete(struct urb *urb) struct out_urb_context *context = urb->context; struct snd_usb_midi_out_endpoint *ep = context->ep; unsigned int urb_index; + unsigned long flags; - spin_lock(&ep->buffer_lock); + spin_lock_irqsave(&ep->buffer_lock, flags); urb_index = context - ep->urbs; ep->active_urbs &= ~(1 << urb_index); if (unlikely(ep->drain_urbs)) { ep->drain_urbs &= ~(1 << urb_index); wake_up(&ep->drain_wait); } - spin_unlock(&ep->buffer_lock); + spin_unlock_irqrestore(&ep->buffer_lock, flags); if (urb->status < 0) { int err = snd_usbmidi_urb_error(urb); if (err < 0) { diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 4ed9d0c41843..edc9f5a34eff 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1854,7 +1854,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) /* setup private data which can be retrieved when required */ pcm->private_data = ctx; pcm->info_flags = 0; - strncpy(pcm->name, card->shortname, strlen(card->shortname)); + strlcpy(pcm->name, card->shortname, strlen(card->shortname)); /* setup the ops for playabck */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &had_pcm_ops); |