From 8d8b7fb9006d8a3831e56e20ad6178cbcb627dea Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Oct 2011 16:27:33 +0800 Subject: [PATCH] --- yaml --- r: 273565 b: refs/heads/master c: b272cc769ac22014c0c60f2ebac46a2ae01300bf h: refs/heads/master i: 273563: 075fdc92f13406939560c94998377cf6e044ac9c v: v3 --- [refs] | 2 +- .../DocBook/writing-an-alsa-driver.tmpl | 36 +- .../sound/alsa/ALSA-Configuration.txt | 6 - .../sound/alsa/HD-Audio-Controls.txt | 16 - .../sound/alsa/HD-Audio-Models.txt | 67 +- trunk/Documentation/sound/alsa/HD-Audio.txt | 55 +- trunk/MAINTAINERS | 2 +- trunk/include/linux/input.h | 1 - trunk/include/linux/usb/ch9.h | 17 +- trunk/include/sound/asound.h | 4 +- trunk/include/sound/initval.h | 2 +- trunk/include/sound/jack.h | 1 - trunk/include/sound/mpu401.h | 7 +- trunk/include/sound/pcm.h | 4 - trunk/sound/aoa/codecs/onyx.c | 4 +- trunk/sound/aoa/fabrics/layout.c | 2 +- trunk/sound/arm/aaci.c | 2 +- trunk/sound/arm/pxa2xx-ac97-lib.c | 2 +- trunk/sound/core/control.c | 84 +- trunk/sound/core/control_compat.c | 4 - trunk/sound/core/hwdep.c | 9 +- trunk/sound/core/jack.c | 1 - trunk/sound/core/oss/mixer_oss.c | 2 +- trunk/sound/core/pcm_lib.c | 59 +- trunk/sound/core/pcm_native.c | 19 +- trunk/sound/core/timer.c | 5 - trunk/sound/drivers/aloop.c | 13 +- trunk/sound/drivers/ml403-ac97cr.c | 4 +- trunk/sound/drivers/mpu401/mpu401.c | 3 +- trunk/sound/drivers/mpu401/mpu401_uart.c | 20 +- trunk/sound/drivers/mtpav.c | 2 +- trunk/sound/drivers/serial-u16550.c | 2 +- trunk/sound/firewire/isight.c | 1 + trunk/sound/firewire/speakers.c | 5 +- trunk/sound/isa/ad1816a/ad1816a.c | 2 +- trunk/sound/isa/ad1816a/ad1816a_lib.c | 2 +- trunk/sound/isa/als100.c | 1 + trunk/sound/isa/azt2320.c | 3 +- trunk/sound/isa/cmi8330.c | 2 +- trunk/sound/isa/cs423x/cs4231.c | 1 + trunk/sound/isa/cs423x/cs4236.c | 3 +- trunk/sound/isa/es1688/es1688.c | 2 +- trunk/sound/isa/es1688/es1688_lib.c | 2 +- trunk/sound/isa/es18xx.c | 6 +- trunk/sound/isa/galaxy/galaxy.c | 3 +- trunk/sound/isa/gus/gus_main.c | 2 +- trunk/sound/isa/gus/gusextreme.c | 3 +- trunk/sound/isa/gus/gusmax.c | 2 +- trunk/sound/isa/gus/interwave.c | 2 +- trunk/sound/isa/msnd/msnd_pinnacle.c | 2 +- trunk/sound/isa/opl3sa2.c | 7 +- trunk/sound/isa/opti9xx/miro.c | 3 +- trunk/sound/isa/opti9xx/opti92x-ad1848.c | 4 +- trunk/sound/isa/sb/jazz16.c | 1 + trunk/sound/isa/sb/sb16.c | 5 +- trunk/sound/isa/sb/sb_common.c | 2 +- trunk/sound/isa/sc6000.c | 3 +- trunk/sound/isa/sscape.c | 3 +- trunk/sound/isa/wavefront/wavefront.c | 5 +- trunk/sound/isa/wss/wss_lib.c | 2 +- trunk/sound/mips/au1x00.c | 4 +- trunk/sound/oss/pas2_pcm.c | 8 +- trunk/sound/oss/pss.c | 6 +- trunk/sound/oss/sound_timer.c | 2 +- trunk/sound/pci/Kconfig | 10 +- trunk/sound/pci/ac97/ac97_patch.c | 1 - trunk/sound/pci/als4000.c | 5 +- trunk/sound/pci/asihpi/hpicmn.c | 5 +- trunk/sound/pci/au88x0/au88x0_mpu401.c | 6 +- trunk/sound/pci/azt3328.c | 16 +- trunk/sound/pci/cmipci.c | 5 +- trunk/sound/pci/ctxfi/ctpcm.c | 2 +- trunk/sound/pci/ctxfi/ctsrc.c | 2 +- trunk/sound/pci/ctxfi/ctvmem.h | 2 +- trunk/sound/pci/emu10k1/emupcm.c | 5 - trunk/sound/pci/es1938.c | 5 +- trunk/sound/pci/es1968.c | 5 +- trunk/sound/pci/fm801.c | 29 +- trunk/sound/pci/hda/Makefile | 3 - trunk/sound/pci/hda/alc260_quirks.c | 304 ++++ trunk/sound/pci/hda/alc262_quirks.c | 530 +++++- trunk/sound/pci/hda/alc268_quirks.c | 636 +++++++ trunk/sound/pci/hda/alc269_quirks.c | 681 ++++++++ trunk/sound/pci/hda/alc662_quirks.c | 1408 ++++++++++++++++ trunk/sound/pci/hda/alc680_quirks.c | 222 +++ trunk/sound/pci/hda/alc861_quirks.c | 725 ++++++++ trunk/sound/pci/hda/alc861vd_quirks.c | 605 +++++++ trunk/sound/pci/hda/alc880_quirks.c | 17 +- trunk/sound/pci/hda/alc882_quirks.c | 85 +- trunk/sound/pci/hda/alc_quirks.c | 13 - trunk/sound/pci/hda/hda_codec.c | 149 +- trunk/sound/pci/hda/hda_eld.c | 72 +- trunk/sound/pci/hda/hda_hwdep.c | 8 +- trunk/sound/pci/hda/hda_intel.c | 235 +-- trunk/sound/pci/hda/hda_local.h | 36 +- trunk/sound/pci/hda/hda_proc.c | 12 +- trunk/sound/pci/hda/hda_trace.h | 117 -- trunk/sound/pci/hda/patch_analog.c | 176 +- trunk/sound/pci/hda/patch_cirrus.c | 10 +- trunk/sound/pci/hda/patch_conexant.c | 223 +-- trunk/sound/pci/hda/patch_hdmi.c | 104 +- trunk/sound/pci/hda/patch_realtek.c | 1466 ++++++----------- trunk/sound/pci/hda/patch_sigmatel.c | 119 +- trunk/sound/pci/hda/patch_via.c | 75 +- trunk/sound/pci/ice1712/ice1712.c | 10 +- trunk/sound/pci/intel8x0.c | 29 +- trunk/sound/pci/maestro3.c | 4 +- trunk/sound/pci/oxygen/oxygen_lib.c | 6 +- trunk/sound/pci/oxygen/xonar_pcm179x.c | 1 - trunk/sound/pci/riptide/riptide.c | 2 +- trunk/sound/pci/rme9652/hdsp.c | 2 +- trunk/sound/pci/rme9652/hdspm.c | 214 ++- trunk/sound/pci/sis7019.c | 4 +- trunk/sound/pci/sonicvibes.c | 7 +- trunk/sound/pci/trident/trident.c | 5 +- trunk/sound/pci/via82xx.c | 13 +- trunk/sound/pci/ymfpci/ymfpci.c | 5 +- trunk/sound/pci/ymfpci/ymfpci_main.c | 32 +- trunk/sound/ppc/keywest.c | 1 + trunk/sound/ppc/snd_ps3.c | 2 +- trunk/sound/soc/au1x/dma.c | 2 +- trunk/sound/soc/codecs/tlv320dac33.c | 2 +- trunk/sound/soc/codecs/wm8940.c | 2 +- trunk/sound/soc/nuc900/nuc900-pcm.c | 2 +- trunk/sound/soc/samsung/ac97.c | 2 +- trunk/sound/soc/sh/fsi.c | 2 +- trunk/sound/soc/txx9/txx9aclc-ac97.c | 2 +- trunk/sound/sparc/amd7930.c | 2 +- trunk/sound/usb/6fire/firmware.c | 25 +- trunk/sound/usb/Kconfig | 2 - trunk/sound/usb/Makefile | 12 +- trunk/sound/usb/caiaq/audio.c | 37 +- trunk/sound/usb/caiaq/device.c | 8 +- trunk/sound/usb/caiaq/device.h | 2 - trunk/sound/usb/caiaq/input.c | 157 +- trunk/sound/usb/card.c | 11 +- trunk/sound/usb/card.h | 2 - trunk/sound/usb/clock.c | 12 +- trunk/sound/usb/endpoint.c | 1199 ++++---------- trunk/sound/usb/endpoint.h | 20 +- trunk/sound/usb/format.c | 4 +- trunk/sound/usb/helper.c | 4 +- trunk/sound/usb/helper.h | 2 +- trunk/sound/usb/midi.c | 27 - trunk/sound/usb/mixer.c | 49 +- trunk/sound/usb/mixer.h | 1 - trunk/sound/usb/mixer_quirks.c | 10 +- trunk/sound/usb/pcm.c | 34 +- trunk/sound/usb/pcm.h | 3 - trunk/sound/usb/quirks-table.h | 65 - trunk/sound/usb/quirks.c | 18 +- trunk/sound/usb/stream.c | 452 ----- trunk/sound/usb/stream.h | 12 - trunk/sound/usb/urb.c | 941 +++++++++++ trunk/sound/usb/urb.h | 21 + trunk/sound/usb/usbaudio.h | 1 - 156 files changed, 7798 insertions(+), 4371 deletions(-) create mode 100644 trunk/sound/pci/hda/alc268_quirks.c create mode 100644 trunk/sound/pci/hda/alc269_quirks.c create mode 100644 trunk/sound/pci/hda/alc662_quirks.c create mode 100644 trunk/sound/pci/hda/alc680_quirks.c create mode 100644 trunk/sound/pci/hda/alc861_quirks.c create mode 100644 trunk/sound/pci/hda/alc861vd_quirks.c delete mode 100644 trunk/sound/pci/hda/hda_trace.h delete mode 100644 trunk/sound/usb/stream.c delete mode 100644 trunk/sound/usb/stream.h create mode 100644 trunk/sound/usb/urb.c create mode 100644 trunk/sound/usb/urb.h diff --git a/[refs] b/[refs] index 6ca4d0047be5..4d1d62538980 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 51e4152a969aa6d2306492ebf143932dcb535c9b +refs/heads/master: b272cc769ac22014c0c60f2ebac46a2ae01300bf diff --git a/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl b/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl index 5de23c007078..598c22f3b3ac 100644 --- a/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl +++ b/trunk/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -4288,7 +4288,7 @@ struct _snd_pcm_runtime { @@ -4343,13 +4343,6 @@ struct _snd_pcm_runtime { by itself to start processing the output stream in the irq handler. - - If the MPU-401 interface shares its interrupt with the other logical - devices on the card, set MPU401_INFO_IRQ_HOOK - (see - below). - - Usually, the port address corresponds to the command port and port + 1 corresponds to the data port. If not, you may change @@ -4382,12 +4375,14 @@ struct _snd_pcm_runtime { - The 6th argument specifies the ISA irq number that will be - allocated. If no interrupt is to be allocated (because your - code is already allocating a shared interrupt, or because the - device does not use interrupts), pass -1 instead. - For a MPU-401 device without an interrupt, a polling timer - will be used instead. + The 6th argument specifies the irq number for UART. If the irq + is already allocated, pass 0 to the 7th argument + (irq_flags). Otherwise, pass the flags + for irq allocation + (SA_XXX bits) to it, and the irq will be + reserved by the mpu401-uart layer. If the card doesn't generate + UART interrupts, pass -1 as the irq number. Then a timer + interrupt will be invoked for polling. @@ -4395,13 +4390,12 @@ struct _snd_pcm_runtime { Interrupt Handler When the interrupt is allocated in - snd_mpu401_uart_new(), an exclusive ISA - interrupt handler is automatically used, hence you don't have - anything else to do than creating the mpu401 stuff. Otherwise, you - have to set MPU401_INFO_IRQ_HOOK, and call - snd_mpu401_uart_interrupt() explicitly from your - own interrupt handler when it has determined that a UART interrupt - has occurred. + snd_mpu401_uart_new(), the private + interrupt handler is used, hence you don't have anything else to do + than creating the mpu401 stuff. Otherwise, you have to call + snd_mpu401_uart_interrupt() explicitly when + a UART interrupt is invoked and checked in your own interrupt + handler. diff --git a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt index 936699e4f04b..89757012c7ff 100644 --- a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt @@ -886,12 +886,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. disable) power_save_controller - Reset HD-audio controller in power-saving mode (default = on) - align_buffer_size - Force rounding of buffer/period sizes to multiples - of 128 bytes. This is more efficient in terms of memory - access but isn't required by the HDA spec and prevents - users from specifying exact period/buffer sizes. - (default = on) - snoop - Enable/disable snooping (default = on) This module supports multiple cards and autoprobe. diff --git a/trunk/Documentation/sound/alsa/HD-Audio-Controls.txt b/trunk/Documentation/sound/alsa/HD-Audio-Controls.txt index e9621e349e17..1482035243e6 100644 --- a/trunk/Documentation/sound/alsa/HD-Audio-Controls.txt +++ b/trunk/Documentation/sound/alsa/HD-Audio-Controls.txt @@ -98,19 +98,3 @@ Conexant codecs * Auto-Mute Mode See Reatek codecs. - - -Analog codecs --------------- - -* Channel Mode - This is an enum control to change the surround-channel setup, - appears only when the surround channels are available. - It gives the number of channels to be used, "2ch", "4ch" and "6ch". - According to the configuration, this also controls the - jack-retasking of multi-I/O jacks. - -* Independent HP - When this enum control is enabled, the headphone output is routed - from an individual stream (the third PCM such as hw:0,2) instead of - the primary stream. diff --git a/trunk/Documentation/sound/alsa/HD-Audio-Models.txt b/trunk/Documentation/sound/alsa/HD-Audio-Models.txt index 4f3443230d89..d70c93bdcadf 100644 --- a/trunk/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/trunk/Documentation/sound/alsa/HD-Audio-Models.txt @@ -29,6 +29,9 @@ ALC880 ALC260 ====== + hp HP machines + hp-3013 HP machines (3013-variant) + hp-dc7600 HP DC7600 fujitsu Fujitsu S7020 acer Acer TravelMate will Will laptops (PB V7900) @@ -43,10 +46,15 @@ ALC260 ALC262 ====== fujitsu Fujitsu Laptop + hp-bpc HP xw4400/6400/8400/9400 laptops + hp-bpc-d7000 HP BPC D7000 + hp-tc-t5735 HP Thin Client T5735 + hp-rp5700 HP RP5700 benq Benq ED8 benq-t31 Benq T31 hippo Hippo (ATI) with jack detection, Sony UX-90s hippo_1 Hippo (Benq) with jack detection + sony-assamd Sony ASSAMD toshiba-s06 Toshiba S06 toshiba-rx1 Toshiba RX1 tyan Tyan Thunder n6650W (S2915-E) @@ -58,15 +66,43 @@ ALC262 ALC267/268 ========== - N/A + quanta-il1 Quanta IL1 mini-notebook + 3stack 3-stack model + toshiba Toshiba A205 + acer Acer laptops + acer-dmic Acer laptops with digital-mic + acer-aspire Acer Aspire One + dell Dell OEM laptops (Vostro 1200) + zepto Zepto laptops + test for testing/debugging purpose, almost all controls can + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) ALC269 ====== + basic Basic preset + quanta Quanta FL1 laptop-amic Laptops with analog-mic input laptop-dmic Laptops with digital-mic input + fujitsu FSC Amilo + lifebook Fujitsu Lifebook S6420 + auto auto-config reading BIOS (default) ALC662/663/272 ============== + 3stack-dig 3-stack (2-channel) with SPDIF + 3stack-6ch 3-stack (6-channel) + 3stack-6ch-dig 3-stack (6-channel) with SPDIF + 5stack-dig 5-stack with SPDIF + lenovo-101e Lenovo laptop + eeepc-p701 ASUS Eeepc P701 + eeepc-ep20 ASUS Eeepc EP20 + ecs ECS/Foxconn mobo + m51va ASUS M51VA + g71v ASUS G71V + h13 ASUS H13 + g50v ASUS G50V asus-mode1 ASUS asus-mode2 ASUS asus-mode3 ASUS @@ -75,10 +111,15 @@ ALC662/663/272 asus-mode6 ASUS asus-mode7 ASUS asus-mode8 ASUS + dell Dell with ALC272 + dell-zm1 Dell ZM1 with ALC272 + samsung-nc10 Samsung NC10 mini notebook + auto auto-config reading BIOS (default) ALC680 ====== - N/A + base Base model (ASUS NX90) + auto auto-config reading BIOS (default) ALC882/883/885/888/889 ====================== @@ -134,11 +175,28 @@ ALC882/883/885/888/889 ALC861/660 ========== - N/A + 3stack 3-jack + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack with SPDIF I/O + 3stack-660 3-jack (for ALC660) + uniwill-m31 Uniwill M31 laptop + toshiba Toshiba laptop support + asus Asus laptop support + asus-laptop ASUS F2/F3 laptops + auto auto-config reading BIOS (default) ALC861VD/660VD ============== - N/A + 3stack 3-jack + 3stack-dig 3-jack with SPDIF OUT + 6stack-dig 6-jack with SPDIF OUT + 3stack-660 3-jack (for ALC660VD) + 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD) + lenovo Lenovo 3000 C200 + dallas Dallas laptops + hp HP TX1000 + asus-v1s ASUS V1Sn + auto auto-config reading BIOS (default) CMI9880 ======= @@ -231,6 +289,7 @@ Conexant 5051 hp-dv6736 HP dv6736 hp-f700 HP Compaq Presario F700 ideapad Lenovo IdeaPad laptop + lenovo-x200 Lenovo X200 laptop toshiba Toshiba Satellite M300 Conexant 5066 diff --git a/trunk/Documentation/sound/alsa/HD-Audio.txt b/trunk/Documentation/sound/alsa/HD-Audio.txt index 03e2771ddeef..c82beb007634 100644 --- a/trunk/Documentation/sound/alsa/HD-Audio.txt +++ b/trunk/Documentation/sound/alsa/HD-Audio.txt @@ -447,10 +447,7 @@ The file needs to have a line `[codec]`. The next line should contain three numbers indicating the codec vendor-id (0x12345678 in the example), the codec subsystem-id (0xabcd1234) and the address (2) of the codec. The rest patch entries are applied to this specified codec -until another codec entry is given. Passing 0 or a negative number to -the first or the second value will make the check of the corresponding -field be skipped. It'll be useful for really broken devices that don't -initialize SSID properly. +until another codec entry is given. The `[model]` line allows to change the model name of the each codec. In the example above, it will be changed to model=auto. @@ -494,7 +491,7 @@ Also, the codec chip name can be rewritten via `[chip_name]` line. The hd-audio driver reads the file via request_firmware(). Thus, a patch file has to be located on the appropriate firmware path, typically, /lib/firmware. For example, when you pass the option -`patch=hda-init.fw`, the file /lib/firmware/hda-init.fw must be +`patch=hda-init.fw`, the file /lib/firmware/hda-init-fw must be present. The patch module option is specific to each card instance, and you @@ -527,54 +524,6 @@ power-saving. See /sys/module/snd_hda_intel/parameters/power_save to check the current value. If it's non-zero, the feature is turned on. -Tracepoints -~~~~~~~~~~~ -The hd-audio driver gives a few basic tracepoints. -`hda:hda_send_cmd` traces each CORB write while `hda:hda_get_response` -traces the response from RIRB (only when read from the codec driver). -`hda:hda_bus_reset` traces the bus-reset due to fatal error, etc, -`hda:hda_unsol_event` traces the unsolicited events, and -`hda:hda_power_down` and `hda:hda_power_up` trace the power down/up -via power-saving behavior. - -Enabling all tracepoints can be done like ------------------------------------------------------------------------- - # echo 1 > /sys/kernel/debug/tracing/events/hda/enable ------------------------------------------------------------------------- -then after some commands, you can traces from -/sys/kernel/debug/tracing/trace file. For example, when you want to -trace what codec command is sent, enable the tracepoint like: ------------------------------------------------------------------------- - # cat /sys/kernel/debug/tracing/trace - # tracer: nop - # - # TASK-PID CPU# TIMESTAMP FUNCTION - # | | | | | - <...>-7807 [002] 105147.774889: hda_send_cmd: [0:0] val=e3a019 - <...>-7807 [002] 105147.774893: hda_send_cmd: [0:0] val=e39019 - <...>-7807 [002] 105147.999542: hda_send_cmd: [0:0] val=e3a01a - <...>-7807 [002] 105147.999543: hda_send_cmd: [0:0] val=e3901a - <...>-26764 [001] 349222.837143: hda_send_cmd: [0:0] val=e3a019 - <...>-26764 [001] 349222.837148: hda_send_cmd: [0:0] val=e39019 - <...>-26764 [001] 349223.058539: hda_send_cmd: [0:0] val=e3a01a - <...>-26764 [001] 349223.058541: hda_send_cmd: [0:0] val=e3901a ------------------------------------------------------------------------- -Here `[0:0]` indicates the card number and the codec address, and -`val` shows the value sent to the codec, respectively. The value is -a packed value, and you can decode it via hda-decode-verb program -included in hda-emu package below. For example, the value e3a019 is -to set the left output-amp value to 25. ------------------------------------------------------------------------- - % hda-decode-verb 0xe3a019 - raw value = 0x00e3a019 - cid = 0, nid = 0x0e, verb = 0x3a0, parm = 0x19 - raw value: verb = 0x3a0, parm = 0x19 - verbname = set_amp_gain_mute - amp raw val = 0xa019 - output, left, idx=0, mute=0, val=25 ------------------------------------------------------------------------- - - Development Tree ~~~~~~~~~~~~~~~~ The latest development codes for HD-audio are found on sound git tree: diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 1dbbb278d218..bbf42cd74e2a 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -5991,7 +5991,7 @@ M: Jaroslav Kysela M: Takashi Iwai L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://www.alsa-project.org/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git T: git git://git.alsa-project.org/alsa-kernel.git S: Maintained F: Documentation/sound/ diff --git a/trunk/include/linux/input.h b/trunk/include/linux/input.h index a514fb8faea3..a637e7814334 100644 --- a/trunk/include/linux/input.h +++ b/trunk/include/linux/input.h @@ -814,7 +814,6 @@ struct input_keymap_entry { #define SW_KEYPAD_SLIDE 0x0a /* set = keypad slide out */ #define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */ #define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ -#define SW_LINEIN_INSERT 0x0d /* set = inserted */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) diff --git a/trunk/include/linux/usb/ch9.h b/trunk/include/linux/usb/ch9.h index f30253599501..0fd3fbdd8283 100644 --- a/trunk/include/linux/usb/ch9.h +++ b/trunk/include/linux/usb/ch9.h @@ -377,23 +377,18 @@ struct usb_endpoint_descriptor { #define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ #define USB_ENDPOINT_DIR_MASK 0x80 -#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ -#define USB_ENDPOINT_XFER_CONTROL 0 -#define USB_ENDPOINT_XFER_ISOC 1 -#define USB_ENDPOINT_XFER_BULK 2 -#define USB_ENDPOINT_XFER_INT 3 -#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 - #define USB_ENDPOINT_SYNCTYPE 0x0c #define USB_ENDPOINT_SYNC_NONE (0 << 2) #define USB_ENDPOINT_SYNC_ASYNC (1 << 2) #define USB_ENDPOINT_SYNC_ADAPTIVE (2 << 2) #define USB_ENDPOINT_SYNC_SYNC (3 << 2) -#define USB_ENDPOINT_USAGE_MASK 0x30 -#define USB_ENDPOINT_USAGE_DATA 0x00 -#define USB_ENDPOINT_USAGE_FEEDBACK 0x10 -#define USB_ENDPOINT_USAGE_IMPLICIT_FB 0x20 /* Implicit feedback Data endpoint */ +#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 /*-------------------------------------------------------------------------*/ diff --git a/trunk/include/sound/asound.h b/trunk/include/sound/asound.h index a2e4ff5ba9e9..5d6074faa279 100644 --- a/trunk/include/sound/asound.h +++ b/trunk/include/sound/asound.h @@ -706,7 +706,7 @@ struct snd_timer_tread { * * ****************************************************************************/ -#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7) +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) struct snd_ctl_card_info { int card; /* card number */ @@ -803,8 +803,6 @@ struct snd_ctl_elem_info { unsigned int items; /* R: number of items */ unsigned int item; /* W: item number */ char name[64]; /* R: value name */ - __u64 names_ptr; /* W: names list (ELEM_ADD only) */ - unsigned int names_length; } enumerated; unsigned char reserved[128]; } value; diff --git a/trunk/include/sound/initval.h b/trunk/include/sound/initval.h index f99a0d2ddfe7..1daa6dff8297 100644 --- a/trunk/include/sound/initval.h +++ b/trunk/include/sound/initval.h @@ -62,7 +62,7 @@ static int snd_legacy_find_free_irq(int *irq_table) { while (*irq_table != -1) { if (!request_irq(*irq_table, snd_legacy_empty_irq_handler, - IRQF_PROBE_SHARED, "ALSA Test IRQ", + IRQF_DISABLED | IRQF_PROBE_SHARED, "ALSA Test IRQ", (void *) irq_table)) { free_irq(*irq_table, (void *) irq_table); return *irq_table; diff --git a/trunk/include/sound/jack.h b/trunk/include/sound/jack.h index 63c790742db4..c140fc7cbd3f 100644 --- a/trunk/include/sound/jack.h +++ b/trunk/include/sound/jack.h @@ -42,7 +42,6 @@ enum snd_jack_types { SND_JACK_MECHANICAL = 0x0008, /* If detected separately */ SND_JACK_VIDEOOUT = 0x0010, SND_JACK_AVOUT = SND_JACK_LINEOUT | SND_JACK_VIDEOOUT, - SND_JACK_LINEIN = 0x0020, /* Kept separate from switches to facilitate implementation */ SND_JACK_BTN_0 = 0x4000, diff --git a/trunk/include/sound/mpu401.h b/trunk/include/sound/mpu401.h index 20230db00ef1..1f1d53f8830b 100644 --- a/trunk/include/sound/mpu401.h +++ b/trunk/include/sound/mpu401.h @@ -50,10 +50,7 @@ #define MPU401_INFO_INTEGRATED (1 << 2) /* integrated h/w port */ #define MPU401_INFO_MMIO (1 << 3) /* MMIO access */ #define MPU401_INFO_TX_IRQ (1 << 4) /* independent TX irq */ -#define MPU401_INFO_IRQ_HOOK (1 << 5) /* mpu401 irq handler is called - from driver irq handler */ #define MPU401_INFO_NO_ACK (1 << 6) /* No ACK cmd needed */ -#define MPU401_INFO_USE_TIMER (1 << 15) /* internal */ #define MPU401_MODE_BIT_INPUT 0 #define MPU401_MODE_BIT_OUTPUT 1 @@ -76,7 +73,8 @@ struct snd_mpu401 { unsigned long port; /* base port of MPU-401 chip */ unsigned long cport; /* port + 1 (usually) */ struct resource *res; /* port resource */ - int irq; /* IRQ number of MPU-401 chip */ + int irq; /* IRQ number of MPU-401 chip (-1 = poll) */ + int irq_flags; unsigned long mode; /* MPU401_MODE_XXXX */ int timer_invoked; @@ -133,6 +131,7 @@ int snd_mpu401_uart_new(struct snd_card *card, unsigned long port, unsigned int info_flags, int irq, + int irq_flags, struct snd_rawmidi ** rrawmidi); #endif /* __SOUND_MPU401_H */ diff --git a/trunk/include/sound/pcm.h b/trunk/include/sound/pcm.h index 3e7fda6e8164..57e71fa33f7c 100644 --- a/trunk/include/sound/pcm.h +++ b/trunk/include/sound/pcm.h @@ -825,8 +825,6 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime, int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, unsigned int cond, snd_pcm_hw_param_t var); -int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime, - unsigned int base_rate); int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, int var, @@ -1037,8 +1035,6 @@ static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area) atomic_dec(&substream->mmap_count); } -int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *area); /* mmap for io-memory area */ #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA) #define SNDRV_PCM_INFO_MMAP_IOMEM SNDRV_PCM_INFO_MMAP diff --git a/trunk/sound/aoa/codecs/onyx.c b/trunk/sound/aoa/codecs/onyx.c index 762af68c8996..3687a6cc9881 100644 --- a/trunk/sound/aoa/codecs/onyx.c +++ b/trunk/sound/aoa/codecs/onyx.c @@ -1067,6 +1067,7 @@ static int onyx_i2c_probe(struct i2c_client *client, printk(KERN_DEBUG PFX "created and attached onyx instance\n"); return 0; fail: + i2c_set_clientdata(client, NULL); kfree(onyx); return -ENODEV; } @@ -1111,7 +1112,8 @@ static int onyx_i2c_remove(struct i2c_client *client) aoa_codec_unregister(&onyx->codec); of_node_put(onyx->codec.node); - kfree(onyx->codec_info); + if (onyx->codec_info) + kfree(onyx->codec_info); kfree(onyx); return 0; } diff --git a/trunk/sound/aoa/fabrics/layout.c b/trunk/sound/aoa/fabrics/layout.c index 552b97afbca5..3fd1a7e24928 100644 --- a/trunk/sound/aoa/fabrics/layout.c +++ b/trunk/sound/aoa/fabrics/layout.c @@ -1073,10 +1073,10 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) sdev->pcmid = -1; list_del(&ldev->list); layouts_list_items--; - kfree(ldev); outnodev: of_node_put(sound); layout_device = NULL; + kfree(ldev); return -ENODEV; } diff --git a/trunk/sound/arm/aaci.c b/trunk/sound/arm/aaci.c index e518d38b1c74..d0cead38d5fb 100644 --- a/trunk/sound/arm/aaci.c +++ b/trunk/sound/arm/aaci.c @@ -443,7 +443,7 @@ static int aaci_pcm_open(struct snd_pcm_substream *substream) mutex_lock(&aaci->irq_lock); if (!aaci->users++) { ret = request_irq(aaci->dev->irq[0], aaci_irq, - IRQF_SHARED, DRIVER_NAME, aaci); + IRQF_SHARED | IRQF_DISABLED, DRIVER_NAME, aaci); if (ret != 0) aaci->users--; } diff --git a/trunk/sound/arm/pxa2xx-ac97-lib.c b/trunk/sound/arm/pxa2xx-ac97-lib.c index 8ad65352bf91..88eec3847df2 100644 --- a/trunk/sound/arm/pxa2xx-ac97-lib.c +++ b/trunk/sound/arm/pxa2xx-ac97-lib.c @@ -359,7 +359,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) if (ret) goto err_clk2; - ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL); + ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL); if (ret < 0) goto err_irq; diff --git a/trunk/sound/core/control.c b/trunk/sound/core/control.c index 978fe1a8e9f0..f8c5be464510 100644 --- a/trunk/sound/core/control.c +++ b/trunk/sound/core/control.c @@ -989,6 +989,7 @@ struct user_element { void *tlv_data; /* TLV data */ unsigned long tlv_data_size; /* TLV data size */ void *priv_data; /* private data (like strings for enumerated type) */ + unsigned long priv_data_size; /* size of private data in bytes */ }; static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol, @@ -1000,28 +1001,6 @@ static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol, return 0; } -static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct user_element *ue = kcontrol->private_data; - const char *names; - unsigned int item; - - item = uinfo->value.enumerated.item; - - *uinfo = ue->info; - - item = min(item, uinfo->value.enumerated.items - 1); - uinfo->value.enumerated.item = item; - - names = ue->priv_data; - for (; item > 0; --item) - names += strlen(names) + 1; - strcpy(uinfo->value.enumerated.name, names); - - return 0; -} - static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1076,46 +1055,11 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, return change; } -static int snd_ctl_elem_init_enum_names(struct user_element *ue) -{ - char *names, *p; - size_t buf_len, name_len; - unsigned int i; - - if (ue->info.value.enumerated.names_length > 64 * 1024) - return -EINVAL; - - names = memdup_user( - (const void __user *)ue->info.value.enumerated.names_ptr, - ue->info.value.enumerated.names_length); - if (IS_ERR(names)) - return PTR_ERR(names); - - /* check that there are enough valid names */ - buf_len = ue->info.value.enumerated.names_length; - p = names; - for (i = 0; i < ue->info.value.enumerated.items; ++i) { - name_len = strnlen(p, buf_len); - if (name_len == 0 || name_len >= 64 || name_len == buf_len) { - kfree(names); - return -EINVAL; - } - p += name_len + 1; - buf_len -= name_len + 1; - } - - ue->priv_data = names; - ue->info.value.enumerated.names_ptr = 0; - - return 0; -} - static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) { struct user_element *ue = kcontrol->private_data; - - kfree(ue->tlv_data); - kfree(ue->priv_data); + if (ue->tlv_data) + kfree(ue->tlv_data); kfree(ue); } @@ -1128,8 +1072,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, long private_size; struct user_element *ue; int idx, err; - - if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS) + + if (card->user_ctl_count >= MAX_USER_CONTROLS) return -ENOMEM; if (info->count < 1) return -EINVAL; @@ -1157,10 +1101,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, memcpy(&kctl.id, &info->id, sizeof(info->id)); kctl.count = info->owner ? info->owner : 1; access |= SNDRV_CTL_ELEM_ACCESS_USER; - if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) - kctl.info = snd_ctl_elem_user_enum_info; - else - kctl.info = snd_ctl_elem_user_info; + kctl.info = snd_ctl_elem_user_info; if (access & SNDRV_CTL_ELEM_ACCESS_READ) kctl.get = snd_ctl_elem_user_get; if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) @@ -1181,11 +1122,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (info->count > 64) return -EINVAL; break; - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - private_size = sizeof(unsigned int); - if (info->count > 128 || info->value.enumerated.items == 0) - return -EINVAL; - break; case SNDRV_CTL_ELEM_TYPE_BYTES: private_size = sizeof(unsigned char); if (info->count > 512) @@ -1207,17 +1143,9 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, ue->info.access = 0; ue->elem_data = (char *)ue + sizeof(*ue); ue->elem_data_size = private_size; - if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { - err = snd_ctl_elem_init_enum_names(ue); - if (err < 0) { - kfree(ue); - return err; - } - } kctl.private_free = snd_ctl_elem_user_free; _kctl = snd_ctl_new(&kctl, access); if (_kctl == NULL) { - kfree(ue->priv_data); kfree(ue); return -ENOMEM; } diff --git a/trunk/sound/core/control_compat.c b/trunk/sound/core/control_compat.c index 2bb95a7a8809..426874429a5e 100644 --- a/trunk/sound/core/control_compat.c +++ b/trunk/sound/core/control_compat.c @@ -83,8 +83,6 @@ struct snd_ctl_elem_info32 { u32 items; u32 item; char name[64]; - u64 names_ptr; - u32 names_length; } enumerated; unsigned char reserved[128]; } value; @@ -374,8 +372,6 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, &data32->value.enumerated, sizeof(data->value.enumerated))) goto error; - data->value.enumerated.names_ptr = - (uintptr_t)compat_ptr(data->value.enumerated.names_ptr); break; default: break; diff --git a/trunk/sound/core/hwdep.c b/trunk/sound/core/hwdep.c index 031e215b6dde..a70ee7f1ed98 100644 --- a/trunk/sound/core/hwdep.c +++ b/trunk/sound/core/hwdep.c @@ -272,14 +272,7 @@ static int snd_hwdep_control_ioctl(struct snd_card *card, if (get_user(device, (int __user *)arg)) return -EFAULT; mutex_lock(®ister_mutex); - - if (device < 0) - device = 0; - else if (device < SNDRV_MINOR_HWDEPS) - device++; - else - device = SNDRV_MINOR_HWDEPS; - + device = device < 0 ? 0 : device + 1; while (device < SNDRV_MINOR_HWDEPS) { if (snd_hwdep_search(card, device)) break; diff --git a/trunk/sound/core/jack.c b/trunk/sound/core/jack.c index 240a3e13470d..53b53e97c896 100644 --- a/trunk/sound/core/jack.c +++ b/trunk/sound/core/jack.c @@ -30,7 +30,6 @@ static int jack_switch_types[] = { SW_LINEOUT_INSERT, SW_JACK_PHYSICAL_INSERT, SW_VIDEOOUT_INSERT, - SW_LINEIN_INSERT, }; static int snd_jack_dev_free(struct snd_device *device) diff --git a/trunk/sound/core/oss/mixer_oss.c b/trunk/sound/core/oss/mixer_oss.c index 1b5e0c49a0ad..d8359cfeca15 100644 --- a/trunk/sound/core/oss/mixer_oss.c +++ b/trunk/sound/core/oss/mixer_oss.c @@ -499,7 +499,7 @@ static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, c memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strlcpy(id.name, name, sizeof(id.name)); + strcpy(id.name, name); id.index = index; return snd_ctl_find_id(card, &id); } diff --git a/trunk/sound/core/pcm_lib.c b/trunk/sound/core/pcm_lib.c index 95d1e789715f..86d0caf91b35 100644 --- a/trunk/sound/core/pcm_lib.c +++ b/trunk/sound/core/pcm_lib.c @@ -1399,32 +1399,6 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); -static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - unsigned int base_rate = (unsigned int)(uintptr_t)rule->private; - struct snd_interval *rate; - - rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - return snd_interval_list(rate, 1, &base_rate, 0); -} - -/** - * snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling - * @runtime: PCM runtime instance - * @base_rate: the rate at which the hardware does not resample - */ -int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime, - unsigned int base_rate) -{ - return snd_pcm_hw_rule_add(runtime, SNDRV_PCM_HW_PARAMS_NORESAMPLE, - SNDRV_PCM_HW_PARAM_RATE, - snd_pcm_hw_rule_noresample_func, - (void *)(uintptr_t)base_rate, - SNDRV_PCM_HW_PARAM_RATE, -1); -} -EXPORT_SYMBOL(snd_pcm_hw_rule_noresample); - static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var) { @@ -1787,10 +1761,6 @@ static int wait_for_avail(struct snd_pcm_substream *substream, snd_pcm_uframes_t avail = 0; long wait_time, tout; - init_waitqueue_entry(&wait, current); - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&runtime->tsleep, &wait); - if (runtime->no_period_wakeup) wait_time = MAX_SCHEDULE_TIMEOUT; else { @@ -1801,32 +1771,16 @@ static int wait_for_avail(struct snd_pcm_substream *substream, } wait_time = msecs_to_jiffies(wait_time * 1000); } - + init_waitqueue_entry(&wait, current); + add_wait_queue(&runtime->tsleep, &wait); for (;;) { if (signal_pending(current)) { err = -ERESTARTSYS; break; } - - /* - * We need to check if space became available already - * (and thus the wakeup happened already) first to close - * the race of space already having become available. - * This check must happen after been added to the waitqueue - * and having current state be INTERRUPTIBLE. - */ - if (is_playback) - avail = snd_pcm_playback_avail(runtime); - else - avail = snd_pcm_capture_avail(runtime); - if (avail >= runtime->twake) - break; snd_pcm_stream_unlock_irq(substream); - - tout = schedule_timeout(wait_time); - + tout = schedule_timeout_interruptible(wait_time); snd_pcm_stream_lock_irq(substream); - set_current_state(TASK_INTERRUPTIBLE); switch (runtime->status->state) { case SNDRV_PCM_STATE_SUSPENDED: err = -ESTRPIPE; @@ -1852,9 +1806,14 @@ static int wait_for_avail(struct snd_pcm_substream *substream, err = -EIO; break; } + if (is_playback) + avail = snd_pcm_playback_avail(runtime); + else + avail = snd_pcm_capture_avail(runtime); + if (avail >= runtime->twake) + break; } _endloop: - set_current_state(TASK_RUNNING); remove_wait_queue(&runtime->tsleep, &wait); *availp = avail; return err; diff --git a/trunk/sound/core/pcm_native.c b/trunk/sound/core/pcm_native.c index 77d7df22e7c8..1c6be91dfb98 100644 --- a/trunk/sound/core/pcm_native.c +++ b/trunk/sound/core/pcm_native.c @@ -2058,12 +2058,16 @@ EXPORT_SYMBOL(snd_pcm_open_substream); static int snd_pcm_open_file(struct file *file, struct snd_pcm *pcm, - int stream) + int stream, + struct snd_pcm_file **rpcm_file) { struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream; int err; + if (rpcm_file) + *rpcm_file = NULL; + err = snd_pcm_open_substream(pcm, stream, file, &substream); if (err < 0) return err; @@ -2079,7 +2083,8 @@ static int snd_pcm_open_file(struct file *file, substream->pcm_release = pcm_release_private; } file->private_data = pcm_file; - + if (rpcm_file) + *rpcm_file = pcm_file; return 0; } @@ -2108,6 +2113,7 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file) static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) { int err; + struct snd_pcm_file *pcm_file; wait_queue_t wait; if (pcm == NULL) { @@ -2125,7 +2131,7 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) add_wait_queue(&pcm->open_wait, &wait); mutex_lock(&pcm->open_mutex); while (1) { - err = snd_pcm_open_file(file, pcm, stream); + err = snd_pcm_open_file(file, pcm, stream, &pcm_file); if (err >= 0) break; if (err == -EAGAIN) { @@ -3150,8 +3156,8 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { /* * mmap the DMA buffer on RAM */ -int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *area) +static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *area) { area->vm_flags |= VM_RESERVED; #ifdef ARCH_HAS_DMA_MMAP_COHERENT @@ -3171,7 +3177,6 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, area->vm_ops = &snd_pcm_vm_ops_data_fault; return 0; } -EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap); /* * mmap the DMA buffer on I/O memory area @@ -3237,7 +3242,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, if (substream->ops->mmap) err = substream->ops->mmap(substream, area); else - err = snd_pcm_lib_default_mmap(substream, area); + err = snd_pcm_default_mmap(substream, area); if (!err) atomic_inc(&substream->mmap_count); return err; diff --git a/trunk/sound/core/timer.c b/trunk/sound/core/timer.c index 67ebf1c21c04..7c1cbf0a0dc4 100644 --- a/trunk/sound/core/timer.c +++ b/trunk/sound/core/timer.c @@ -328,8 +328,6 @@ int snd_timer_close(struct snd_timer_instance *timeri) mutex_unlock(®ister_mutex); } else { timer = timeri->timer; - if (snd_BUG_ON(!timer)) - goto out; /* wait, until the active callback is finished */ spin_lock_irq(&timer->lock); while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { @@ -355,7 +353,6 @@ int snd_timer_close(struct snd_timer_instance *timeri) } mutex_unlock(®ister_mutex); } - out: if (timeri->private_free) timeri->private_free(timeri); kfree(timeri->owner); @@ -534,8 +531,6 @@ int snd_timer_stop(struct snd_timer_instance *timeri) if (err < 0) return err; timer = timeri->timer; - if (!timer) - return -EINVAL; spin_lock_irqsave(&timer->lock, flags); timeri->cticks = timeri->ticks; timeri->pticks = 0; diff --git a/trunk/sound/drivers/aloop.c b/trunk/sound/drivers/aloop.c index 4067f1548949..a0da7755fcea 100644 --- a/trunk/sound/drivers/aloop.c +++ b/trunk/sound/drivers/aloop.c @@ -575,8 +575,7 @@ static void loopback_runtime_free(struct snd_pcm_runtime *runtime) static int loopback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(params)); + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); } static int loopback_hw_free(struct snd_pcm_substream *substream) @@ -588,7 +587,7 @@ static int loopback_hw_free(struct snd_pcm_substream *substream) mutex_lock(&dpcm->loopback->cable_lock); cable->valid &= ~(1 << substream->stream); mutex_unlock(&dpcm->loopback->cable_lock); - return snd_pcm_lib_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_pages(substream); } static unsigned int get_cable_index(struct snd_pcm_substream *substream) @@ -741,8 +740,6 @@ static struct snd_pcm_ops loopback_playback_ops = { .prepare = loopback_prepare, .trigger = loopback_trigger, .pointer = loopback_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops loopback_capture_ops = { @@ -754,8 +751,6 @@ static struct snd_pcm_ops loopback_capture_ops = { .prepare = loopback_prepare, .trigger = loopback_trigger, .pointer = loopback_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static int __devinit loopback_pcm_new(struct loopback *loopback, @@ -776,6 +771,10 @@ static int __devinit loopback_pcm_new(struct loopback *loopback, strcpy(pcm->name, "Loopback PCM"); loopback->pcm[device] = pcm; + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 0, 2 * 1024 * 1024); return 0; } diff --git a/trunk/sound/drivers/ml403-ac97cr.c b/trunk/sound/drivers/ml403-ac97cr.c index 2c7a7636f472..5cfcb908c430 100644 --- a/trunk/sound/drivers/ml403-ac97cr.c +++ b/trunk/sound/drivers/ml403-ac97cr.c @@ -1153,7 +1153,7 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev, "0x%x done\n", (unsigned int)ml403_ac97cr->port); /* get irq */ irq = platform_get_irq(pfdev, 0); - if (request_irq(irq, snd_ml403_ac97cr_irq, 0, + if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, dev_name(&pfdev->dev), (void *)ml403_ac97cr)) { snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " "unable to grab IRQ %d\n", @@ -1166,7 +1166,7 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev, "request (playback) irq %d done\n", ml403_ac97cr->irq); irq = platform_get_irq(pfdev, 1); - if (request_irq(irq, snd_ml403_ac97cr_irq, 0, + if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, dev_name(&pfdev->dev), (void *)ml403_ac97cr)) { snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " "unable to grab IRQ %d\n", diff --git a/trunk/sound/drivers/mpu401/mpu401.c b/trunk/sound/drivers/mpu401/mpu401.c index 1c02852aceea..149d05a8202d 100644 --- a/trunk/sound/drivers/mpu401/mpu401.c +++ b/trunk/sound/drivers/mpu401/mpu401.c @@ -86,7 +86,8 @@ static int snd_mpu401_create(int dev, struct snd_card **rcard) } err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port[dev], 0, - irq[dev], NULL); + irq[dev], irq[dev] >= 0 ? IRQF_DISABLED : 0, + NULL); if (err < 0) { printk(KERN_ERR "MPU401 not detected at 0x%lx\n", port[dev]); goto _err; diff --git a/trunk/sound/drivers/mpu401/mpu401_uart.c b/trunk/sound/drivers/mpu401/mpu401_uart.c index e91698a634b2..2af09996a3d0 100644 --- a/trunk/sound/drivers/mpu401/mpu401_uart.c +++ b/trunk/sound/drivers/mpu401/mpu401_uart.c @@ -3,7 +3,7 @@ * Routines for control of MPU-401 in UART mode * * MPU-401 supports UART mode which is not capable generate transmit - * interrupts thus output is done via polling. Without interrupt, + * interrupts thus output is done via polling. Also, if irq < 0, then * input is done also via polling. Do not expect good performance. * * @@ -374,7 +374,7 @@ snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) /* first time - flush FIFO */ while (max-- > 0) mpu->read(mpu, MPU401D(mpu)); - if (mpu->info_flags & MPU401_INFO_USE_TIMER) + if (mpu->irq < 0) snd_mpu401_uart_add_timer(mpu, 1); } @@ -383,7 +383,7 @@ snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) snd_mpu401_uart_input_read(mpu); spin_unlock_irqrestore(&mpu->input_lock, flags); } else { - if (mpu->info_flags & MPU401_INFO_USE_TIMER) + if (mpu->irq < 0) snd_mpu401_uart_remove_timer(mpu, 1); clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode); } @@ -496,7 +496,7 @@ static struct snd_rawmidi_ops snd_mpu401_uart_input = static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) { struct snd_mpu401 *mpu = rmidi->private_data; - if (mpu->irq >= 0) + if (mpu->irq_flags && mpu->irq >= 0) free_irq(mpu->irq, (void *) mpu); release_and_free_resource(mpu->res); kfree(mpu); @@ -509,7 +509,8 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) * @hardware: the hardware type, MPU401_HW_XXXX * @port: the base address of MPU401 port * @info_flags: bitflags MPU401_INFO_XXX - * @irq: the ISA irq number, -1 if not to be allocated + * @irq: the irq number, -1 if no interrupt for mpu + * @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved. * @rrawmidi: the pointer to store the new rawmidi instance * * Creates a new MPU-401 instance. @@ -524,7 +525,7 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, unsigned short hardware, unsigned long port, unsigned int info_flags, - int irq, + int irq, int irq_flags, struct snd_rawmidi ** rrawmidi) { struct snd_mpu401 *mpu; @@ -576,8 +577,8 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, mpu->cport = port + 2; else mpu->cport = port + 1; - if (irq >= 0) { - if (request_irq(irq, snd_mpu401_uart_interrupt, 0, + if (irq >= 0 && irq_flags) { + if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags, "MPU401 UART", (void *) mpu)) { snd_printk(KERN_ERR "mpu401_uart: " "unable to grab IRQ %d\n", irq); @@ -585,10 +586,9 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, return -EBUSY; } } - if (irq < 0 && !(info_flags & MPU401_INFO_IRQ_HOOK)) - info_flags |= MPU401_INFO_USE_TIMER; mpu->info_flags = info_flags; mpu->irq = irq; + mpu->irq_flags = irq_flags; if (card->shortname[0]) snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", card->shortname); diff --git a/trunk/sound/drivers/mtpav.c b/trunk/sound/drivers/mtpav.c index 1eef4ccebe4b..5c426df87678 100644 --- a/trunk/sound/drivers/mtpav.c +++ b/trunk/sound/drivers/mtpav.c @@ -589,7 +589,7 @@ static int __devinit snd_mtpav_get_ISA(struct mtpav * mcard) return -EBUSY; } mcard->port = port; - if (request_irq(irq, snd_mtpav_irqh, 0, "MOTU MTPAV", mcard)) { + if (request_irq(irq, snd_mtpav_irqh, IRQF_DISABLED, "MOTU MTPAV", mcard)) { snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq); return -EBUSY; } diff --git a/trunk/sound/drivers/serial-u16550.c b/trunk/sound/drivers/serial-u16550.c index fc1d822802c3..a25fb7b1f441 100644 --- a/trunk/sound/drivers/serial-u16550.c +++ b/trunk/sound/drivers/serial-u16550.c @@ -816,7 +816,7 @@ static int __devinit snd_uart16550_create(struct snd_card *card, if (irq >= 0 && irq != SNDRV_AUTO_IRQ) { if (request_irq(irq, snd_uart16550_interrupt, - 0, "Serial MIDI", uart)) { + IRQF_DISABLED, "Serial MIDI", uart)) { snd_printk(KERN_WARNING "irq %d busy. Using Polling.\n", irq); } else { diff --git a/trunk/sound/firewire/isight.c b/trunk/sound/firewire/isight.c index cd094ecaca3b..440030818db7 100644 --- a/trunk/sound/firewire/isight.c +++ b/trunk/sound/firewire/isight.c @@ -51,6 +51,7 @@ struct isight { struct fw_unit *unit; struct fw_device *device; u64 audio_base; + struct fw_address_handler iris_handler; struct snd_pcm_substream *pcm; struct mutex mutex; struct iso_packets_buffer buffer; diff --git a/trunk/sound/firewire/speakers.c b/trunk/sound/firewire/speakers.c index cbe6bb9e53b6..3fc257da180c 100644 --- a/trunk/sound/firewire/speakers.c +++ b/trunk/sound/firewire/speakers.c @@ -778,10 +778,9 @@ static int __devexit fwspk_remove(struct device *dev) { struct fwspk *fwspk = dev_get_drvdata(dev); + mutex_lock(&fwspk->mutex); amdtp_out_stream_pcm_abort(&fwspk->stream); snd_card_disconnect(fwspk->card); - - mutex_lock(&fwspk->mutex); fwspk_stop_stream(fwspk); mutex_unlock(&fwspk->mutex); @@ -797,8 +796,8 @@ static void fwspk_bus_reset(struct fw_unit *unit) fcp_bus_reset(fwspk->unit); if (cmp_connection_update(&fwspk->connection) < 0) { - amdtp_out_stream_pcm_abort(&fwspk->stream); mutex_lock(&fwspk->mutex); + amdtp_out_stream_pcm_abort(&fwspk->stream); fwspk_stop_stream(fwspk); mutex_unlock(&fwspk->mutex); return; diff --git a/trunk/sound/isa/ad1816a/ad1816a.c b/trunk/sound/isa/ad1816a/ad1816a.c index a87a2b566e19..3cb75bc97699 100644 --- a/trunk/sound/isa/ad1816a/ad1816a.c +++ b/trunk/sound/isa/ad1816a/ad1816a.c @@ -204,7 +204,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard if (mpu_port[dev] > 0) { if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - mpu_port[dev], 0, mpu_irq[dev], + mpu_port[dev], 0, mpu_irq[dev], IRQF_DISABLED, NULL) < 0) printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", mpu_port[dev]); } diff --git a/trunk/sound/isa/ad1816a/ad1816a_lib.c b/trunk/sound/isa/ad1816a/ad1816a_lib.c index 177eed3271bc..05aef8b97e96 100644 --- a/trunk/sound/isa/ad1816a/ad1816a_lib.c +++ b/trunk/sound/isa/ad1816a/ad1816a_lib.c @@ -595,7 +595,7 @@ int __devinit snd_ad1816a_create(struct snd_card *card, snd_ad1816a_free(chip); return -EBUSY; } - if (request_irq(irq, snd_ad1816a_interrupt, 0, "AD1816A", (void *) chip)) { + if (request_irq(irq, snd_ad1816a_interrupt, IRQF_DISABLED, "AD1816A", (void *) chip)) { snd_printk(KERN_ERR "ad1816a: can't grab IRQ %d\n", irq); snd_ad1816a_free(chip); return -EBUSY; diff --git a/trunk/sound/isa/als100.c b/trunk/sound/isa/als100.c index 706effd6b3cd..20becc89f6f6 100644 --- a/trunk/sound/isa/als100.c +++ b/trunk/sound/isa/als100.c @@ -256,6 +256,7 @@ static int __devinit snd_card_als100_probe(int dev, mpu_type, mpu_port[dev], 0, mpu_irq[dev], + mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, NULL) < 0) snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); } diff --git a/trunk/sound/isa/azt2320.c b/trunk/sound/isa/azt2320.c index b7bdbf307740..aac8dc15c2fe 100644 --- a/trunk/sound/isa/azt2320.c +++ b/trunk/sound/isa/azt2320.c @@ -234,7 +234,8 @@ static int __devinit snd_card_azt2320_probe(int dev, if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320, mpu_port[dev], 0, - mpu_irq[dev], NULL) < 0) + mpu_irq[dev], IRQF_DISABLED, + NULL) < 0) snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); } diff --git a/trunk/sound/isa/cmi8330.c b/trunk/sound/isa/cmi8330.c index dca69f80305f..fe79a169acb5 100644 --- a/trunk/sound/isa/cmi8330.c +++ b/trunk/sound/isa/cmi8330.c @@ -597,7 +597,7 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) if (mpuport[dev] != SNDRV_AUTO_PORT) { if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, mpuport[dev], 0, mpuirq[dev], - NULL) < 0) + IRQF_DISABLED, NULL) < 0) printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", mpuport[dev]); } diff --git a/trunk/sound/isa/cs423x/cs4231.c b/trunk/sound/isa/cs423x/cs4231.c index 409fa0ad7843..cb9153e75b82 100644 --- a/trunk/sound/isa/cs423x/cs4231.c +++ b/trunk/sound/isa/cs423x/cs4231.c @@ -131,6 +131,7 @@ static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n) mpu_irq[n] = -1; if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232, mpu_port[n], 0, mpu_irq[n], + mpu_irq[n] >= 0 ? IRQF_DISABLED : 0, NULL) < 0) dev_warn(dev, "MPU401 not detected\n"); } diff --git a/trunk/sound/isa/cs423x/cs4236.c b/trunk/sound/isa/cs423x/cs4236.c index 0dbde461e6c1..999dc1e0fdbd 100644 --- a/trunk/sound/isa/cs423x/cs4236.c +++ b/trunk/sound/isa/cs423x/cs4236.c @@ -449,7 +449,8 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) mpu_irq[dev] = -1; if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232, mpu_port[dev], 0, - mpu_irq[dev], NULL) < 0) + mpu_irq[dev], + mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, NULL) < 0) printk(KERN_WARNING IDENT ": MPU401 not detected\n"); } diff --git a/trunk/sound/isa/es1688/es1688.c b/trunk/sound/isa/es1688/es1688.c index 5493e9e4bcd5..0cde8131a575 100644 --- a/trunk/sound/isa/es1688/es1688.c +++ b/trunk/sound/isa/es1688/es1688.c @@ -174,7 +174,7 @@ static int __devinit snd_es1688_probe(struct snd_card *card, unsigned int n) chip->mpu_port > 0) { error = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688, chip->mpu_port, 0, - mpu_irq[n], NULL); + mpu_irq[n], IRQF_DISABLED, NULL); if (error < 0) return error; } diff --git a/trunk/sound/isa/es1688/es1688_lib.c b/trunk/sound/isa/es1688/es1688_lib.c index d3eab6fb0866..07676200496a 100644 --- a/trunk/sound/isa/es1688/es1688_lib.c +++ b/trunk/sound/isa/es1688/es1688_lib.c @@ -661,7 +661,7 @@ int snd_es1688_create(struct snd_card *card, snd_printk(KERN_ERR "es1688: can't grab port 0x%lx\n", port + 4); return -EBUSY; } - if (request_irq(irq, snd_es1688_interrupt, 0, "ES1688", (void *) chip)) { + if (request_irq(irq, snd_es1688_interrupt, IRQF_DISABLED, "ES1688", (void *) chip)) { snd_printk(KERN_ERR "es1688: can't grab IRQ %d\n", irq); return -EBUSY; } diff --git a/trunk/sound/isa/es18xx.c b/trunk/sound/isa/es18xx.c index bf6ad0bf51c6..fb4d6b34bbca 100644 --- a/trunk/sound/isa/es18xx.c +++ b/trunk/sound/isa/es18xx.c @@ -1805,7 +1805,7 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card, return -EBUSY; } - if (request_irq(irq, snd_es18xx_interrupt, 0, "ES18xx", + if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx", (void *) card)) { snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq); @@ -2160,8 +2160,8 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, - mpu_port[dev], MPU401_INFO_IRQ_HOOK, - -1, &chip->rmidi); + mpu_port[dev], 0, + irq[dev], 0, &chip->rmidi); if (err < 0) return err; } diff --git a/trunk/sound/isa/galaxy/galaxy.c b/trunk/sound/isa/galaxy/galaxy.c index e51d3244742a..ee54df082b9c 100644 --- a/trunk/sound/isa/galaxy/galaxy.c +++ b/trunk/sound/isa/galaxy/galaxy.c @@ -585,7 +585,8 @@ static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n) if (mpu_port[n] >= 0) { err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - mpu_port[n], 0, mpu_irq[n], NULL); + mpu_port[n], 0, mpu_irq[n], + IRQF_DISABLED, NULL); if (err < 0) goto error; } diff --git a/trunk/sound/isa/gus/gus_main.c b/trunk/sound/isa/gus/gus_main.c index 3167e5ac3699..12eb98f2f931 100644 --- a/trunk/sound/isa/gus/gus_main.c +++ b/trunk/sound/isa/gus/gus_main.c @@ -180,7 +180,7 @@ int snd_gus_create(struct snd_card *card, snd_gus_free(gus); return -EBUSY; } - if (irq >= 0 && request_irq(irq, snd_gus_interrupt, 0, "GUS GF1", (void *) gus)) { + if (irq >= 0 && request_irq(irq, snd_gus_interrupt, IRQF_DISABLED, "GUS GF1", (void *) gus)) { snd_printk(KERN_ERR "gus: can't grab irq %d\n", irq); snd_gus_free(gus); return -EBUSY; diff --git a/trunk/sound/isa/gus/gusextreme.c b/trunk/sound/isa/gus/gusextreme.c index c4733c08b60b..008e8e5bfa37 100644 --- a/trunk/sound/isa/gus/gusextreme.c +++ b/trunk/sound/isa/gus/gusextreme.c @@ -317,7 +317,8 @@ static int __devinit snd_gusextreme_probe(struct device *dev, unsigned int n) if (es1688->mpu_port >= 0x300) { error = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688, - es1688->mpu_port, 0, mpu_irq[n], NULL); + es1688->mpu_port, 0, + mpu_irq[n], IRQF_DISABLED, NULL); if (error < 0) goto out; } diff --git a/trunk/sound/isa/gus/gusmax.c b/trunk/sound/isa/gus/gusmax.c index c43faa057ff6..3e4a58b72913 100644 --- a/trunk/sound/isa/gus/gusmax.c +++ b/trunk/sound/isa/gus/gusmax.c @@ -291,7 +291,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) goto _err; } - if (request_irq(xirq, snd_gusmax_interrupt, 0, "GUS MAX", (void *)maxcard)) { + if (request_irq(xirq, snd_gusmax_interrupt, IRQF_DISABLED, "GUS MAX", (void *)maxcard)) { snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq); err = -EBUSY; goto _err; diff --git a/trunk/sound/isa/gus/interwave.c b/trunk/sound/isa/gus/interwave.c index 5f869a32b48c..c7b80e4730fc 100644 --- a/trunk/sound/isa/gus/interwave.c +++ b/trunk/sound/isa/gus/interwave.c @@ -684,7 +684,7 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev) if ((err = snd_gus_initialize(gus)) < 0) return err; - if (request_irq(xirq, snd_interwave_interrupt, 0, + if (request_irq(xirq, snd_interwave_interrupt, IRQF_DISABLED, "InterWave", iwcard)) { snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq); return -EBUSY; diff --git a/trunk/sound/isa/msnd/msnd_pinnacle.c b/trunk/sound/isa/msnd/msnd_pinnacle.c index 0961e2cf20ca..91d6023a63e5 100644 --- a/trunk/sound/isa/msnd/msnd_pinnacle.c +++ b/trunk/sound/isa/msnd/msnd_pinnacle.c @@ -600,7 +600,7 @@ static int __devinit snd_msnd_attach(struct snd_card *card) mpu_io[0], MPU401_MODE_INPUT | MPU401_MODE_OUTPUT, - mpu_irq[0], + mpu_irq[0], IRQF_DISABLED, &chip->rmidi); if (err < 0) { printk(KERN_ERR LOGNAME diff --git a/trunk/sound/isa/opl3sa2.c b/trunk/sound/isa/opl3sa2.c index bbafb0b543ea..9b915e27b5bd 100644 --- a/trunk/sound/isa/opl3sa2.c +++ b/trunk/sound/isa/opl3sa2.c @@ -667,7 +667,7 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev) err = snd_opl3sa2_detect(card); if (err < 0) return err; - err = request_irq(xirq, snd_opl3sa2_interrupt, 0, + err = request_irq(xirq, snd_opl3sa2_interrupt, IRQF_DISABLED, "OPL3-SA2", card); if (err) { snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq); @@ -707,9 +707,8 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev) } if (midi_port[dev] >= 0x300 && midi_port[dev] < 0x340) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_OPL3SA2, - midi_port[dev], - MPU401_INFO_IRQ_HOOK, -1, - &chip->rmidi)) < 0) + midi_port[dev], 0, + xirq, 0, &chip->rmidi)) < 0) return err; } sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", diff --git a/trunk/sound/isa/opti9xx/miro.c b/trunk/sound/isa/opti9xx/miro.c index d94d0f35cb76..8c24102d0d93 100644 --- a/trunk/sound/isa/opti9xx/miro.c +++ b/trunk/sound/isa/opti9xx/miro.c @@ -1377,7 +1377,8 @@ static int __devinit snd_miro_probe(struct snd_card *card) rmidi = NULL; else { error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - mpu_port, 0, miro->mpu_irq, &rmidi); + mpu_port, 0, miro->mpu_irq, IRQF_DISABLED, + &rmidi); if (error < 0) snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", mpu_port); diff --git a/trunk/sound/isa/opti9xx/opti92x-ad1848.c b/trunk/sound/isa/opti9xx/opti92x-ad1848.c index 6dbbfa76b440..c35dc68930dc 100644 --- a/trunk/sound/isa/opti9xx/opti92x-ad1848.c +++ b/trunk/sound/isa/opti9xx/opti92x-ad1848.c @@ -892,7 +892,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) #endif #ifdef OPTi93X error = request_irq(irq, snd_opti93x_interrupt, - 0, DEV_NAME" - WSS", chip); + IRQF_DISABLED, DEV_NAME" - WSS", chip); if (error < 0) { snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", irq); return error; @@ -914,7 +914,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) rmidi = NULL; else { error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - mpu_port, 0, mpu_irq, &rmidi); + mpu_port, 0, mpu_irq, IRQF_DISABLED, &rmidi); if (error) snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", mpu_port); diff --git a/trunk/sound/isa/sb/jazz16.c b/trunk/sound/isa/sb/jazz16.c index 54e3c2c18060..8ccbcddf08e1 100644 --- a/trunk/sound/isa/sb/jazz16.c +++ b/trunk/sound/isa/sb/jazz16.c @@ -322,6 +322,7 @@ static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev) MPU401_HW_MPU401, mpu_port[dev], 0, mpu_irq[dev], + mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, NULL) < 0) snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n", mpu_port[dev]); diff --git a/trunk/sound/isa/sb/sb16.c b/trunk/sound/isa/sb/sb16.c index 237f8bd7fbe4..4d1c5a300ff8 100644 --- a/trunk/sound/isa/sb/sb16.c +++ b/trunk/sound/isa/sb/sb16.c @@ -394,9 +394,8 @@ static int __devinit snd_sb16_probe(struct snd_card *card, int dev) if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB, - chip->mpu_port, - MPU401_INFO_IRQ_HOOK, -1, - &chip->rmidi)) < 0) + chip->mpu_port, 0, + xirq, 0, &chip->rmidi)) < 0) return err; chip->rmidi_callback = snd_mpu401_uart_interrupt; } diff --git a/trunk/sound/isa/sb/sb_common.c b/trunk/sound/isa/sb/sb_common.c index d2e19215813e..eae6c1c0eff9 100644 --- a/trunk/sound/isa/sb/sb_common.c +++ b/trunk/sound/isa/sb/sb_common.c @@ -240,7 +240,7 @@ int snd_sbdsp_create(struct snd_card *card, if (request_irq(irq, irq_handler, (hardware == SB_HW_ALS4000 || hardware == SB_HW_CS5530) ? - IRQF_SHARED : 0, + IRQF_SHARED : IRQF_DISABLED, "SoundBlaster", (void *) chip)) { snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq); snd_sbdsp_free(chip); diff --git a/trunk/sound/isa/sc6000.c b/trunk/sound/isa/sc6000.c index 207c161f100c..9a8bbf6dd62a 100644 --- a/trunk/sound/isa/sc6000.c +++ b/trunk/sound/isa/sc6000.c @@ -658,7 +658,8 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, mpu_port[dev], 0, - mpu_irq[dev], NULL) < 0) + mpu_irq[dev], IRQF_DISABLED, + NULL) < 0) snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]); } diff --git a/trunk/sound/isa/sscape.c b/trunk/sound/isa/sscape.c index f2379e102b63..e2d5d2d3ed96 100644 --- a/trunk/sound/isa/sscape.c +++ b/trunk/sound/isa/sscape.c @@ -825,7 +825,8 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, int err; err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port, - MPU401_INFO_INTEGRATED, irq, &rawmidi); + MPU401_INFO_INTEGRATED, irq, IRQF_DISABLED, + &rawmidi); if (err == 0) { struct snd_mpu401 *mpu = rawmidi->private_data; mpu->open_input = mpu401_open; diff --git a/trunk/sound/isa/wavefront/wavefront.c b/trunk/sound/isa/wavefront/wavefront.c index 87142977335a..711670e4a425 100644 --- a/trunk/sound/isa/wavefront/wavefront.c +++ b/trunk/sound/isa/wavefront/wavefront.c @@ -418,7 +418,7 @@ snd_wavefront_probe (struct snd_card *card, int dev) return -EBUSY; } if (request_irq(ics2115_irq[dev], snd_wavefront_ics2115_interrupt, - 0, "ICS2115", acard)) { + IRQF_DISABLED, "ICS2115", acard)) { snd_printk(KERN_ERR "unable to use ICS2115 IRQ %d\n", ics2115_irq[dev]); return -EBUSY; } @@ -449,7 +449,8 @@ snd_wavefront_probe (struct snd_card *card, int dev) if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) { err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232, cs4232_mpu_port[dev], 0, - cs4232_mpu_irq[dev], NULL); + cs4232_mpu_irq[dev], IRQF_DISABLED, + NULL); if (err < 0) { snd_printk (KERN_ERR "can't allocate CS4232 MPU-401 device\n"); return err; diff --git a/trunk/sound/isa/wss/wss_lib.c b/trunk/sound/isa/wss/wss_lib.c index 7277c5b7df6c..2a42cc377957 100644 --- a/trunk/sound/isa/wss/wss_lib.c +++ b/trunk/sound/isa/wss/wss_lib.c @@ -1833,7 +1833,7 @@ int snd_wss_create(struct snd_card *card, } chip->cport = cport; if (!(hwshare & WSS_HWSHARE_IRQ)) - if (request_irq(irq, snd_wss_interrupt, 0, + if (request_irq(irq, snd_wss_interrupt, IRQF_DISABLED, "WSS", (void *) chip)) { snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq); snd_wss_free(chip); diff --git a/trunk/sound/mips/au1x00.c b/trunk/sound/mips/au1x00.c index 7567ebd71913..446cf9748664 100644 --- a/trunk/sound/mips/au1x00.c +++ b/trunk/sound/mips/au1x00.c @@ -465,13 +465,13 @@ snd_au1000_pcm_new(struct snd_au1000 *au1000) flags = claim_dma_lock(); if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX, - "AC97 TX", au1000_dma_interrupt, 0, + "AC97 TX", au1000_dma_interrupt, IRQF_DISABLED, au1000->stream[PLAYBACK])) < 0) { release_dma_lock(flags); return -EBUSY; } if ((au1000->stream[CAPTURE]->dma = request_au1000_dma(DMA_ID_AC97C_RX, - "AC97 RX", au1000_dma_interrupt, 0, + "AC97 RX", au1000_dma_interrupt, IRQF_DISABLED, au1000->stream[CAPTURE])) < 0){ release_dma_lock(flags); return -EBUSY; diff --git a/trunk/sound/oss/pas2_pcm.c b/trunk/sound/oss/pas2_pcm.c index 6f13ab4afc6b..8f7d175767a2 100644 --- a/trunk/sound/oss/pas2_pcm.c +++ b/trunk/sound/oss/pas2_pcm.c @@ -63,13 +63,13 @@ static int pcm_set_speed(int arg) if (pcm_channels & 2) { - foo = ((PIT_TICK_RATE / 2) + (arg / 2)) / arg; - arg = ((PIT_TICK_RATE / 2) + (foo / 2)) / foo; + foo = ((CLOCK_TICK_RATE / 2) + (arg / 2)) / arg; + arg = ((CLOCK_TICK_RATE / 2) + (foo / 2)) / foo; } else { - foo = (PIT_TICK_RATE + (arg / 2)) / arg; - arg = (PIT_TICK_RATE + (foo / 2)) / foo; + foo = (CLOCK_TICK_RATE + (arg / 2)) / arg; + arg = (CLOCK_TICK_RATE + (foo / 2)) / foo; } pcm_speed = arg; diff --git a/trunk/sound/oss/pss.c b/trunk/sound/oss/pss.c index 2fc0624024b5..9b800ce5100e 100644 --- a/trunk/sound/oss/pss.c +++ b/trunk/sound/oss/pss.c @@ -673,8 +673,7 @@ static void configure_nonsound_components(void) if (pss_cdrom_port == -1) { /* If cdrom port enablation wasn't requested */ printk(KERN_INFO "PSS: CDROM port not enabled.\n"); - } else if (!request_region(pss_cdrom_port, 2, "PSS CDROM")) { - pss_cdrom_port = -1; + } else if (check_region(pss_cdrom_port, 2)) { printk(KERN_ERR "PSS: CDROM I/O port conflict.\n"); } else { set_io_base(devc, CONF_CDROM, pss_cdrom_port); @@ -1233,8 +1232,7 @@ static void __exit cleanup_pss(void) if(pssmpu) unload_pss_mpu(&cfg_mpu); unload_pss(&cfg); - } else if (pss_cdrom_port != -1) - release_region(pss_cdrom_port, 2); + } if(!pss_keep_settings) /* Keep hardware settings if asked */ { diff --git a/trunk/sound/oss/sound_timer.c b/trunk/sound/oss/sound_timer.c index 8021c85f076d..48cda6c4c257 100644 --- a/trunk/sound/oss/sound_timer.c +++ b/trunk/sound/oss/sound_timer.c @@ -320,7 +320,7 @@ void sound_timer_init(struct sound_lowlev_timer *t, char *name) n = sound_alloc_timerdev(); if (n == -1) n = 0; /* Overwrite the system timer */ - strlcpy(sound_timer.info.name, name, sizeof(sound_timer.info.name)); + strcpy(sound_timer.info.name, name); sound_timer_devs[n] = &sound_timer; } EXPORT_SYMBOL(sound_timer_init); diff --git a/trunk/sound/pci/Kconfig b/trunk/sound/pci/Kconfig index 88168044375f..50abf5bf8e09 100644 --- a/trunk/sound/pci/Kconfig +++ b/trunk/sound/pci/Kconfig @@ -1,10 +1,5 @@ # ALSA PCI drivers -config SND_TEA575X - tristate - depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO || RADIO_SF16FMR2 - default SND_FM801 || SND_ES1968 || RADIO_SF16FMR2 - menuconfig SND_PCI bool "PCI sound devices" depends on PCI @@ -568,6 +563,11 @@ config SND_FM801_TEA575X_BOOL FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and SF64-PCR) into the snd-fm801 driver. +config SND_TEA575X + tristate + depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO || RADIO_SF16FMR2 + default SND_FM801 || SND_ES1968 || RADIO_SF16FMR2 + source "sound/pci/hda/Kconfig" config SND_HDSP diff --git a/trunk/sound/pci/ac97/ac97_patch.c b/trunk/sound/pci/ac97/ac97_patch.c index a872d0a82976..200c9a1d48b7 100644 --- a/trunk/sound/pci/ac97/ac97_patch.c +++ b/trunk/sound/pci/ac97/ac97_patch.c @@ -1909,7 +1909,6 @@ static unsigned int ad1981_jacks_whitelist[] = { 0x103c0944, /* HP nc6220 */ 0x103c0934, /* HP nc8220 */ 0x103c006d, /* HP nx9105 */ - 0x103c300d, /* HP Compaq dc5100 SFF(PT003AW) */ 0x17340088, /* FSC Scenic-W */ 0 /* end */ }; diff --git a/trunk/sound/pci/als4000.c b/trunk/sound/pci/als4000.c index 04628696eb08..a9c1af33f276 100644 --- a/trunk/sound/pci/als4000.c +++ b/trunk/sound/pci/als4000.c @@ -931,9 +931,8 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000, iobase + ALS4K_IOB_30_MIDI_DATA, - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &chip->rmidi)) < 0) { + MPU401_INFO_INTEGRATED, + pci->irq, 0, &chip->rmidi)) < 0) { printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", iobase + ALS4K_IOB_30_MIDI_DATA); goto out_err; diff --git a/trunk/sound/pci/asihpi/hpicmn.c b/trunk/sound/pci/asihpi/hpicmn.c index bd47521b24ec..65b7ca13115b 100644 --- a/trunk/sound/pci/asihpi/hpicmn.c +++ b/trunk/sound/pci/asihpi/hpicmn.c @@ -631,12 +631,13 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, if (!p_cache) return NULL; - p_cache->p_info = kzalloc(sizeof(*p_cache->p_info) * control_count, - GFP_KERNEL); + p_cache->p_info = + kmalloc(sizeof(*p_cache->p_info) * control_count, GFP_KERNEL); if (!p_cache->p_info) { kfree(p_cache); return NULL; } + memset(p_cache->p_info, 0, sizeof(*p_cache->p_info) * control_count); p_cache->cache_size_in_bytes = size_in_bytes; p_cache->control_count = control_count; p_cache->p_cache = p_dsp_control_buffer; diff --git a/trunk/sound/pci/au88x0/au88x0_mpu401.c b/trunk/sound/pci/au88x0/au88x0_mpu401.c index e6c6a0febb75..0dc8d259d1ed 100644 --- a/trunk/sound/pci/au88x0/au88x0_mpu401.c +++ b/trunk/sound/pci/au88x0/au88x0_mpu401.c @@ -84,7 +84,7 @@ static int __devinit snd_vortex_midi(vortex_t * vortex) #ifdef VORTEX_MPU401_LEGACY if ((temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330, - MPU401_INFO_IRQ_HOOK, -1, &rmidi)) != 0) { + 0, 0, 0, &rmidi)) != 0) { hwwrite(vortex->mmio, VORTEX_CTRL, (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); @@ -94,8 +94,8 @@ static int __devinit snd_vortex_midi(vortex_t * vortex) port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); if ((temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, - MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO | - MPU401_INFO_IRQ_HOOK, -1, &rmidi)) != 0) { + MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO, + 0, 0, &rmidi)) != 0) { hwwrite(vortex->mmio, VORTEX_CTRL, (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); diff --git a/trunk/sound/pci/azt3328.c b/trunk/sound/pci/azt3328.c index d24fe425e87f..e4d76a270c9f 100644 --- a/trunk/sound/pci/azt3328.c +++ b/trunk/sound/pci/azt3328.c @@ -2625,19 +2625,16 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) int err; snd_azf3328_dbgcallenter(); - if (dev >= SNDRV_CARDS) { - err = -ENODEV; - goto out; - } + if (dev >= SNDRV_CARDS) + return -ENODEV; if (!enable[dev]) { dev++; - err = -ENOENT; - goto out; + return -ENOENT; } err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); if (err < 0) - goto out; + return err; strcpy(card->driver, "AZF3328"); strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); @@ -2652,9 +2649,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) since our hardware ought to be similar, thus use same ID. */ err = snd_mpu401_uart_new( card, 0, - MPU401_HW_AZT2320, chip->mpu_io, - MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, - -1, &chip->rmidi + MPU401_HW_AZT2320, chip->mpu_io, MPU401_INFO_INTEGRATED, + pci->irq, 0, &chip->rmidi ); if (err < 0) { snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", diff --git a/trunk/sound/pci/cmipci.c b/trunk/sound/pci/cmipci.c index da9c73211eca..9cf99fb7eb9c 100644 --- a/trunk/sound/pci/cmipci.c +++ b/trunk/sound/pci/cmipci.c @@ -3228,9 +3228,8 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, iomidi, (integrated_midi ? - MPU401_INFO_INTEGRATED : 0) | - MPU401_INFO_IRQ_HOOK, - -1, &cm->rmidi)) < 0) { + MPU401_INFO_INTEGRATED : 0), + cm->irq, 0, &cm->rmidi)) < 0) { printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi); } } diff --git a/trunk/sound/pci/ctxfi/ctpcm.c b/trunk/sound/pci/ctxfi/ctpcm.c index 2c8622617c8c..457d21189b0d 100644 --- a/trunk/sound/pci/ctxfi/ctpcm.c +++ b/trunk/sound/pci/ctxfi/ctpcm.c @@ -404,7 +404,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc, int err; int playback_count, capture_count; - playback_count = (IEC958 == device) ? 1 : 256; + playback_count = (IEC958 == device) ? 1 : 8; capture_count = (FRONT == device) ? 1 : 0; err = snd_pcm_new(atc->card, "ctxfi", device, playback_count, capture_count, &pcm); diff --git a/trunk/sound/pci/ctxfi/ctsrc.c b/trunk/sound/pci/ctxfi/ctsrc.c index e134b3a5780d..c749fa720889 100644 --- a/trunk/sound/pci/ctxfi/ctsrc.c +++ b/trunk/sound/pci/ctxfi/ctsrc.c @@ -20,7 +20,7 @@ #include "cthardware.h" #include -#define SRC_RESOURCE_NUM 256 +#define SRC_RESOURCE_NUM 64 #define SRCIMP_RESOURCE_NUM 256 static unsigned int conj_mask; diff --git a/trunk/sound/pci/ctxfi/ctvmem.h b/trunk/sound/pci/ctxfi/ctvmem.h index e6da60eb19ce..b23adfca4de6 100644 --- a/trunk/sound/pci/ctxfi/ctvmem.h +++ b/trunk/sound/pci/ctxfi/ctvmem.h @@ -18,7 +18,7 @@ #ifndef CTVMEM_H #define CTVMEM_H -#define CT_PTP_NUM 4 /* num of device page table pages */ +#define CT_PTP_NUM 1 /* num of device page table pages */ #include #include diff --git a/trunk/sound/pci/emu10k1/emupcm.c b/trunk/sound/pci/emu10k1/emupcm.c index e22b8e2bbd88..622bace148e3 100644 --- a/trunk/sound/pci/emu10k1/emupcm.c +++ b/trunk/sound/pci/emu10k1/emupcm.c @@ -1146,11 +1146,6 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream) kfree(epcm); return err; } - err = snd_pcm_hw_rule_noresample(runtime, 48000); - if (err < 0) { - kfree(epcm); - return err; - } mix = &emu->pcm_mixer[substream->number]; for (i = 0; i < 4; i++) mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i; diff --git a/trunk/sound/pci/es1938.c b/trunk/sound/pci/es1938.c index 718a2643474e..26a5a2f25d4b 100644 --- a/trunk/sound/pci/es1938.c +++ b/trunk/sound/pci/es1938.c @@ -1854,9 +1854,8 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, } } if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - chip->mpu_port, - MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, - -1, &chip->rmidi) < 0) { + chip->mpu_port, MPU401_INFO_INTEGRATED, + chip->irq, 0, &chip->rmidi) < 0) { printk(KERN_ERR "es1938: unable to initialize MPU-401\n"); } else { // this line is vital for MIDI interrupt handling on ess-solo1 diff --git a/trunk/sound/pci/es1968.c b/trunk/sound/pci/es1968.c index 407e4abc4356..99ea9320c6b5 100644 --- a/trunk/sound/pci/es1968.c +++ b/trunk/sound/pci/es1968.c @@ -2843,9 +2843,8 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci, if (enable_mpu[dev]) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, chip->io_port + ESM_MPU401_PORT, - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &chip->rmidi)) < 0) { + MPU401_INFO_INTEGRATED, + chip->irq, 0, &chip->rmidi)) < 0) { printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n"); } } diff --git a/trunk/sound/pci/fm801.c b/trunk/sound/pci/fm801.c index 136f7232bb7c..f9123f09e83e 100644 --- a/trunk/sound/pci/fm801.c +++ b/trunk/sound/pci/fm801.c @@ -68,7 +68,6 @@ MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); module_param_array(tea575x_tuner, int, NULL, 0444); MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only)."); -#define TUNER_DISABLED (1<<3) #define TUNER_ONLY (1<<4) #define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF) @@ -729,14 +728,11 @@ static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = { { .data = 2, .clk = 0, .wren = 1, .most = 3, .name = "SF64-PCR" }, }; -#define get_tea575x_gpio(chip) \ - (&snd_fm801_tea575x_gpios[((chip)->tea575x_tuner & TUNER_TYPE_MASK) - 1]) - static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) { struct fm801 *chip = tea->private_data; unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); - struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); + struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; reg &= ~(FM801_GPIO_GP(gpio.data) | FM801_GPIO_GP(gpio.clk) | @@ -754,7 +750,7 @@ static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea) { struct fm801 *chip = tea->private_data; unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); - struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); + struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; return (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 | (reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0; @@ -764,7 +760,7 @@ static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output { struct fm801 *chip = tea->private_data; unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); - struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); + struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; /* use GPIO lines and set write enable bit */ reg |= FM801_GPIO_GS(gpio.data) | @@ -1154,8 +1150,7 @@ static int snd_fm801_free(struct fm801 *chip) __end_hw: #ifdef CONFIG_SND_FM801_TEA575X_BOOL - if (!(chip->tea575x_tuner & TUNER_DISABLED)) - snd_tea575x_exit(&chip->tea); + snd_tea575x_exit(&chip->tea); #endif if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -1241,6 +1236,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, (tea575x_tuner & TUNER_TYPE_MASK) < 4) { if (snd_tea575x_init(&chip->tea)) { snd_printk(KERN_ERR "TEA575x radio not found\n"); + snd_fm801_free(chip); return -ENODEV; } } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) { @@ -1249,19 +1245,17 @@ static int __devinit snd_fm801_create(struct snd_card *card, chip->tea575x_tuner = tea575x_tuner; if (!snd_tea575x_init(&chip->tea)) { snd_printk(KERN_INFO "detected TEA575x radio type %s\n", - get_tea575x_gpio(chip)->name); + snd_fm801_tea575x_gpios[tea575x_tuner - 1].name); break; } } if (tea575x_tuner == 4) { snd_printk(KERN_ERR "TEA575x radio not found\n"); - chip->tea575x_tuner = TUNER_DISABLED; + snd_fm801_free(chip); + return -ENODEV; } } - if (!(chip->tea575x_tuner & TUNER_DISABLED)) { - strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name, - sizeof(chip->tea.card)); - } + strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card)); #endif *rchip = chip; @@ -1312,9 +1306,8 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, } if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801, FM801_REG(chip, MPU401_DATA), - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &chip->rmidi)) < 0) { + MPU401_INFO_INTEGRATED, + chip->irq, 0, &chip->rmidi)) < 0) { snd_card_free(card); return err; } diff --git a/trunk/sound/pci/hda/Makefile b/trunk/sound/pci/hda/Makefile index f928d6634723..87365d5ea2a9 100644 --- a/trunk/sound/pci/hda/Makefile +++ b/trunk/sound/pci/hda/Makefile @@ -6,9 +6,6 @@ snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o -# for trace-points -CFLAGS_hda_codec.o := -I$(src) - snd-hda-codec-realtek-objs := patch_realtek.o snd-hda-codec-cmedia-objs := patch_cmedia.o snd-hda-codec-analog-objs := patch_analog.o diff --git a/trunk/sound/pci/hda/alc260_quirks.c b/trunk/sound/pci/hda/alc260_quirks.c index 3b5170b9700f..21ec2cb100b0 100644 --- a/trunk/sound/pci/hda/alc260_quirks.c +++ b/trunk/sound/pci/hda/alc260_quirks.c @@ -7,6 +7,9 @@ enum { ALC260_AUTO, ALC260_BASIC, + ALC260_HP, + ALC260_HP_DC7600, + ALC260_HP_3013, ALC260_FUJITSU_S702X, ALC260_ACER, ALC260_WILL, @@ -139,6 +142,8 @@ static const struct hda_channel_mode alc260_modes[1] = { /* Mixer combinations * * basic: base_output + input + pc_beep + capture + * HP: base_output + input + capture_alt + * HP_3013: hp_3013 + input + capture * fujitsu: fujitsu + capture * acer: acer + capture */ @@ -165,6 +170,145 @@ static const struct snd_kcontrol_new alc260_input_mixer[] = { { } /* end */ }; +/* update HP, line and mono out pins according to the master switch */ +static void alc260_hp_master_update(struct hda_codec *codec) +{ + update_speakers(codec); +} + +static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + *ucontrol->value.integer.value = !spec->master_mute; + return 0; +} + +static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int val = !*ucontrol->value.integer.value; + + if (val == spec->master_mute) + return 0; + spec->master_mute = val; + alc260_hp_master_update(codec); + return 1; +} + +static const struct snd_kcontrol_new alc260_hp_output_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, + .info = snd_ctl_boolean_mono_info, + .get = alc260_hp_master_sw_get, + .put = alc260_hp_master_sw_put, + }, + HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc260_hp_unsol_verbs[] = { + {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {}, +}; + +static void alc260_hp_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x0f; + spec->autocfg.speaker_pins[0] = 0x10; + spec->autocfg.speaker_pins[1] = 0x11; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, + .info = snd_ctl_boolean_mono_info, + .get = alc260_hp_master_sw_get, + .put = alc260_hp_master_sw_put, + }, + HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static void alc260_hp_3013_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x10; + spec->autocfg.speaker_pins[1] = 0x11; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc260_dc7600_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol), + HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct hda_verb alc260_hp_3013_unsol_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {}, +}; + +static void alc260_hp_3012_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x10; + spec->autocfg.speaker_pins[0] = 0x0f; + spec->autocfg.speaker_pins[1] = 0x11; + spec->autocfg.speaker_pins[2] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + /* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. */ @@ -336,6 +480,106 @@ static const struct hda_verb alc260_init_verbs[] = { { } }; +#if 0 /* should be identical with alc260_init_verbs? */ +static const struct hda_verb alc260_hp_init_verbs[] = { + /* Headphone and output */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + /* mono output */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Line In pin widget for input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* Line-2 pin widget for output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* CD pin widget for input */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* unmute amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to line in (default select for this ADC) */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* unmute Line-Out mixer amp left and right (volume = 0) */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* unmute HP mixer amp left and right (volume = 0) */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & + * Line In 2 = 0x03 + */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* Unmute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + { } +}; +#endif + +static const struct hda_verb alc260_hp_3013_init_verbs[] = { + /* Line out and output */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* mono output */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Line In pin widget for input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* Headphone pin widget for output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + /* CD pin widget for input */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* unmute amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to line in (default select for this ADC) */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* unmute Line-Out mixer amp left and right (volume = 0) */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* unmute HP mixer amp left and right (volume = 0) */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* mute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & + * Line In 2 = 0x03 + */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* Unmute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* Unmute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + { } +}; + /* Initialisation sequence for ALC260 as configured in Fujitsu S702x * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD * audio = 0x16, internal speaker = 0x10. @@ -849,6 +1093,9 @@ static const struct hda_verb alc260_test_init_verbs[] = { */ static const char * const alc260_models[ALC260_MODEL_LAST] = { [ALC260_BASIC] = "basic", + [ALC260_HP] = "hp", + [ALC260_HP_3013] = "hp-3013", + [ALC260_HP_DC7600] = "hp-dc7600", [ALC260_FUJITSU_S702X] = "fujitsu", [ALC260_ACER] = "acer", [ALC260_WILL] = "will", @@ -865,6 +1112,15 @@ static const struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), + SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */ + SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), + SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), + SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP), + SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP), SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), @@ -888,6 +1144,54 @@ static const struct alc_config_preset alc260_presets[] = { .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, }, + [ALC260_HP] = { + .mixers = { alc260_hp_output_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_init_verbs, + alc260_hp_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_setup, + .init_hook = alc_inithook, + }, + [ALC260_HP_DC7600] = { + .mixers = { alc260_hp_dc7600_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_init_verbs, + alc260_hp_dc7600_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_3012_setup, + .init_hook = alc_inithook, + }, + [ALC260_HP_3013] = { + .mixers = { alc260_hp_3013_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_hp_3013_init_verbs, + alc260_hp_3013_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_3013_setup, + .init_hook = alc_inithook, + }, [ALC260_FUJITSU_S702X] = { .mixers = { alc260_fujitsu_mixer }, .init_verbs = { alc260_fujitsu_init_verbs }, diff --git a/trunk/sound/pci/hda/alc262_quirks.c b/trunk/sound/pci/hda/alc262_quirks.c index 7894b2b5aacf..8d2097d77642 100644 --- a/trunk/sound/pci/hda/alc262_quirks.c +++ b/trunk/sound/pci/hda/alc262_quirks.c @@ -10,7 +10,13 @@ enum { ALC262_HIPPO, ALC262_HIPPO_1, ALC262_FUJITSU, + ALC262_HP_BPC, + ALC262_HP_BPC_D7000_WL, + ALC262_HP_BPC_D7000_WF, + ALC262_HP_TC_T5735, + ALC262_HP_RP5700, ALC262_BENQ_ED8, + ALC262_SONY_ASSAMD, ALC262_BENQ_T31, ALC262_ULTRA, ALC262_LENOVO_3000, @@ -60,31 +66,164 @@ static const struct snd_kcontrol_new alc262_base_mixer[] = { { } /* end */ }; -/* bind hp and internal speaker mute (with plug check) as master switch */ +/* update HP, line and mono-out pins according to the master switch */ +#define alc262_hp_master_update alc260_hp_master_update -static int alc262_hippo_master_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc262_hp_bpc_setup(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - *ucontrol->value.integer.value = !spec->master_mute; - return 0; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } -static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc262_hp_wildwest_setup(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - int val = !*ucontrol->value.integer.value; - if (val == spec->master_mute) - return 0; - spec->master_mute = val; - update_outputs(codec); - return 1; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } +#define alc262_hp_master_sw_get alc260_hp_master_sw_get +#define alc262_hp_master_sw_put alc260_hp_master_sw_put + +#define ALC262_HP_MASTER_SWITCH \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Switch", \ + .info = snd_ctl_boolean_mono_info, \ + .get = alc262_hp_master_sw_get, \ + .put = alc262_hp_master_sw_put, \ + }, \ + { \ + .iface = NID_MAPPING, \ + .name = "Master Playback Switch", \ + .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \ + } + + +static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { + ALC262_HP_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { + ALC262_HP_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { + HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_hp_t5735_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_hp_t5735_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + { } +}; + +static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_verb alc262_hp_rp5700_verbs[] = { + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, + {} +}; + +static const struct hda_input_mux alc262_hp_rp5700_capture_source = { + .num_items = 1, + .items = { + { "Line", 0x1 }, + }, +}; + +/* bind hp and internal speaker mute (with plug check) as master switch */ +#define alc262_hippo_master_update alc262_hp_master_update +#define alc262_hippo_master_sw_get alc262_hp_master_sw_get +#define alc262_hippo_master_sw_put alc262_hp_master_sw_put + #define ALC262_HIPPO_MASTER_SWITCH \ { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ @@ -100,9 +239,6 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, (SUBDEV_SPEAKER(0) << 16), \ } -#define alc262_hp_master_sw_get alc262_hippo_master_sw_get -#define alc262_hp_master_sw_put alc262_hippo_master_sw_put - static const struct snd_kcontrol_new alc262_hippo_mixer[] = { ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), @@ -143,7 +279,8 @@ static void alc262_hippo_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc262_hippo1_setup(struct hda_codec *codec) @@ -152,7 +289,8 @@ static void alc262_hippo1_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } @@ -215,7 +353,8 @@ static void alc262_tyan_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x15; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } @@ -357,7 +496,8 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec) spec->ext_mic_pin = 0x18; spec->int_mic_pin = 0x12; spec->auto_mic = 1; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_PIN); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } /* @@ -431,6 +571,27 @@ static const struct hda_input_mux alc262_fujitsu_capture_source = { }, }; +static const struct hda_input_mux alc262_HP_capture_source = { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "AUX IN", 0x6 }, + }, +}; + +static const struct hda_input_mux alc262_HP_D7000_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x2 }, + { "Line", 0x1 }, + { "CD", 0x4 }, + }, +}; + static void alc262_fujitsu_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -438,7 +599,8 @@ static void alc262_fujitsu_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.hp_pins[1] = 0x1b; spec->autocfg.speaker_pins[0] = 0x15; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* bind volumes of both NID 0x0c and 0x0d */ @@ -484,7 +646,8 @@ static void alc262_lenovo_3000_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { @@ -589,8 +752,8 @@ static void alc262_ultra_automute(struct hda_codec *codec) mute = 0; /* auto-mute only when HP is used as HP */ if (!spec->cur_mux[0]) { - spec->hp_jack_present = snd_hda_jack_detect(codec, 0x15); - if (spec->hp_jack_present) + spec->jack_present = snd_hda_jack_detect(codec, 0x15); + if (spec->jack_present) mute = HDA_AMP_MUTE; } /* mute/unmute internal speaker */ @@ -654,6 +817,206 @@ static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { { } /* end */ }; +static const struct hda_verb alc262_HP_BPC_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for + * front panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */ + /* Input mixer1: only unmute Mic */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + + { } +}; + +static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for front + * panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */ + + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/ + /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, + + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + + { } +}; + static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */ @@ -679,8 +1042,13 @@ static const char * const alc262_models[ALC262_MODEL_LAST] = { [ALC262_HIPPO] = "hippo", [ALC262_HIPPO_1] = "hippo_1", [ALC262_FUJITSU] = "fujitsu", + [ALC262_HP_BPC] = "hp-bpc", + [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", + [ALC262_HP_TC_T5735] = "hp-tc-t5735", + [ALC262_HP_RP5700] = "hp-rp5700", [ALC262_BENQ_ED8] = "benq", [ALC262_BENQ_T31] = "benq-t31", + [ALC262_SONY_ASSAMD] = "sony-assamd", [ALC262_TOSHIBA_S06] = "toshiba-s06", [ALC262_TOSHIBA_RX1] = "toshiba-rx1", [ALC262_ULTRA] = "ultra", @@ -693,6 +1061,41 @@ static const char * const alc262_models[ALC262_MODEL_LAST] = { static const struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series", + ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", + ALC262_AUTO), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series", + ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735", + ALC262_HP_TC_T5735), + SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700), + SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), + SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ + SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), + SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO), + SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO), +#if 0 /* disable the quirk since model=auto works better in recent versions */ + SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", + ALC262_SONY_ASSAMD), +#endif SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", ALC262_TOSHIBA_RX1), SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), @@ -763,6 +1166,68 @@ static const struct alc_config_preset alc262_presets[] = { .setup = alc262_fujitsu_setup, .init_hook = alc_inithook, }, + [ALC262_HP_BPC] = { + .mixers = { alc262_HP_BPC_mixer }, + .init_verbs = { alc262_HP_BPC_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_bpc_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_BPC_D7000_WF] = { + .mixers = { alc262_HP_BPC_WildWest_mixer }, + .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_D7000_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_wildwest_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_BPC_D7000_WL] = { + .mixers = { alc262_HP_BPC_WildWest_mixer, + alc262_HP_BPC_WildWest_option_mixer }, + .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_D7000_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_wildwest_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_TC_T5735] = { + .mixers = { alc262_hp_t5735_mixer }, + .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_t5735_setup, + .init_hook = alc_inithook, + }, + [ALC262_HP_RP5700] = { + .mixers = { alc262_hp_rp5700_mixer }, + .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_hp_rp5700_capture_source, + }, [ALC262_BENQ_ED8] = { .mixers = { alc262_base_mixer }, .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, @@ -773,6 +1238,19 @@ static const struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, }, + [ALC262_SONY_ASSAMD] = { + .mixers = { alc262_sony_mixer }, + .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hippo_setup, + .init_hook = alc_inithook, + }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, diff --git a/trunk/sound/pci/hda/alc268_quirks.c b/trunk/sound/pci/hda/alc268_quirks.c new file mode 100644 index 000000000000..be58bf2f3aec --- /dev/null +++ b/trunk/sound/pci/hda/alc268_quirks.c @@ -0,0 +1,636 @@ +/* + * ALC267/ALC268 quirk models + * included by patch_realtek.c + */ + +/* ALC268 models */ +enum { + ALC268_AUTO, + ALC267_QUANTA_IL1, + ALC268_3ST, + ALC268_TOSHIBA, + ALC268_ACER, + ALC268_ACER_DMIC, + ALC268_ACER_ASPIRE_ONE, + ALC268_DELL, + ALC268_ZEPTO, +#ifdef CONFIG_SND_DEBUG + ALC268_TEST, +#endif + ALC268_MODEL_LAST /* last tag */ +}; + +/* + * ALC268 channel source setting (2 channel) + */ +#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID +#define alc268_modes alc260_modes + +static const hda_nid_t alc268_dac_nids[2] = { + /* front, hp */ + 0x02, 0x03 +}; + +static const hda_nid_t alc268_adc_nids[2] = { + /* ADC0-1 */ + 0x08, 0x07 +}; + +static const hda_nid_t alc268_adc_nids_alt[1] = { + /* ADC0 */ + 0x08 +}; + +static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 }; + +static const struct snd_kcontrol_new alc268_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc268_toshiba_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +static const struct hda_verb alc268_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +/* Toshiba specific */ +static const struct hda_verb alc268_toshiba_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +/* Acer specific */ +/* bind volumes of both NID 0x02 and 0x03 */ +static const struct hda_bind_ctls alc268_acer_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static void alc268_acer_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +#define alc268_acer_master_sw_get alc262_hp_master_sw_get +#define alc268_acer_master_sw_put alc262_hp_master_sw_put + +static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x15, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, + .put = alc268_acer_master_sw_put, + }, + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc268_acer_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, + .put = alc268_acer_master_sw_put, + }, + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, + .put = alc268_acer_master_sw_put, + }, + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), + { } +}; + +static const struct hda_verb alc268_acer_aspire_one_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x23, AC_VERB_SET_CONNECT_SEL, 0x06}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017}, + { } +}; + +static const struct hda_verb alc268_acer_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + { } +}; + +/* unsolicited event for HP jack sensing */ +#define alc268_toshiba_setup alc262_hippo_setup + +static void alc268_acer_lc_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x12; + spec->auto_mic = 1; +} + +static const struct snd_kcontrol_new alc268_dell_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct hda_verb alc268_dell_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, + { } +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc268_dell_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct hda_verb alc267_quanta_il1_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, + { } +}; + +static void alc267_quanta_il1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc268_base_init_verbs[] = { + /* Unmute DAC0-1 and set vol = 0 */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + /* set PCBEEP vol = 0, mute connections */ + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + /* Unmute Selector 23h,24h and set the default input to mic-in */ + + {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + { } +}; + +/* only for model=test */ +#ifdef CONFIG_SND_DEBUG +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc268_volume_init_verbs[] = { + /* set output DAC */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + { } +}; +#endif /* CONFIG_SND_DEBUG */ + +static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), + _DEFINE_CAPSRC(1), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc268_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT), + _DEFINE_CAPSRC(2), + { } /* end */ +}; + +static const struct hda_input_mux alc268_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x3 }, + }, +}; + +static const struct hda_input_mux alc268_acer_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; + +static const struct hda_input_mux alc268_acer_dmic_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x6 }, + { "Line", 0x2 }, + }, +}; + +#ifdef CONFIG_SND_DEBUG +static const struct snd_kcontrol_new alc268_test_mixer[] = { + /* Volume widgets */ + HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT), + HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT), + HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT), + HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT), + HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT), + HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT), + /* The below appears problematic on some hardwares */ + /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/ + HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT), + + /* Modes for retasking pin widgets */ + ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT), + + /* Controls for GPIO pins, assuming they are configured as outputs */ + ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), + ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), + ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), + ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), + + /* Switches to allow the digital SPDIF output pin to be enabled. + * The ALC268 does not have an SPDIF input. + */ + ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01), + + /* A switch allowing EAPD to be enabled. Some laptops seem to use + * this output to turn on an external amplifier. + */ + ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), + ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), + + { } /* end */ +}; +#endif + +/* + * configuration and preset + */ +static const char * const alc268_models[ALC268_MODEL_LAST] = { + [ALC267_QUANTA_IL1] = "quanta-il1", + [ALC268_3ST] = "3stack", + [ALC268_TOSHIBA] = "toshiba", + [ALC268_ACER] = "acer", + [ALC268_ACER_DMIC] = "acer-dmic", + [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", + [ALC268_DELL] = "dell", + [ALC268_ZEPTO] = "zepto", +#ifdef CONFIG_SND_DEBUG + [ALC268_TEST] = "test", +#endif + [ALC268_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc268_cfg_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", + ALC268_ACER_ASPIRE_ONE), + SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), + SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO), + SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0, + "Dell Inspiron Mini9/Vostro A90", ALC268_DELL), + /* almost compatible with toshiba but with optional digital outs; + * auto-probing seems working fine + */ + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series", + ALC268_AUTO), + SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), + SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), + SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), + {} +}; + +/* Toshiba laptops have no unique PCI SSID but only codec SSID */ +static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { + SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO), + SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO), + SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", + ALC268_TOSHIBA), + {} +}; + +static const struct alc_config_preset alc268_presets[] = { + [ALC267_QUANTA_IL1] = { + .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer, + alc268_capture_nosrc_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc267_quanta_il1_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc267_quanta_il1_setup, + .init_hook = alc_inithook, + }, + [ALC268_3ST] = { + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC268_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + }, + [ALC268_TOSHIBA] = { + .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_toshiba_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_toshiba_setup, + .init_hook = alc_inithook, + }, + [ALC268_ACER] = { + .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_acer_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_setup, + .init_hook = alc_inithook, + }, + [ALC268_ACER_DMIC] = { + .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_acer_dmic_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_setup, + .init_hook = alc_inithook, + }, + [ALC268_ACER_ASPIRE_ONE] = { + .mixers = { alc268_acer_aspire_one_mixer, + alc268_beep_mixer, + alc268_capture_nosrc_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_aspire_one_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_lc_setup, + .init_hook = alc_inithook, + }, + [ALC268_DELL] = { + .mixers = { alc268_dell_mixer, alc268_beep_mixer, + alc268_capture_nosrc_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_dell_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_dell_setup, + .init_hook = alc_inithook, + }, + [ALC268_ZEPTO] = { + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_toshiba_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC268_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_toshiba_setup, + .init_hook = alc_inithook, + }, +#ifdef CONFIG_SND_DEBUG + [ALC268_TEST] = { + .mixers = { alc268_test_mixer, alc268_capture_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_volume_init_verbs, + alc268_beep_init_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC268_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + }, +#endif +}; + diff --git a/trunk/sound/pci/hda/alc269_quirks.c b/trunk/sound/pci/hda/alc269_quirks.c new file mode 100644 index 000000000000..14fdcf29b154 --- /dev/null +++ b/trunk/sound/pci/hda/alc269_quirks.c @@ -0,0 +1,681 @@ +/* + * ALC269/ALC270/ALC275/ALC276 quirk models + * included by patch_realtek.c + */ + +/* ALC269 models */ +enum { + ALC269_AUTO, + ALC269_BASIC, + ALC269_QUANTA_FL1, + ALC269_AMIC, + ALC269_DMIC, + ALC269VB_AMIC, + ALC269VB_DMIC, + ALC269_FUJITSU, + ALC269_LIFEBOOK, + ALC271_ACER, + ALC269_MODEL_LAST /* last tag */ +}; + +/* + * ALC269 channel source setting (2 channel) + */ +#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID + +#define alc269_dac_nids alc260_dac_nids + +static const hda_nid_t alc269_adc_nids[1] = { + /* ADC1 */ + 0x08, +}; + +static const hda_nid_t alc269_capsrc_nids[1] = { + 0x23, +}; + +static const hda_nid_t alc269vb_adc_nids[1] = { + /* ADC1 */ + 0x09, +}; + +static const hda_nid_t alc269vb_capsrc_nids[1] = { + 0x22, +}; + +#define alc269_modes alc260_modes +#define alc269_capture_source alc880_lg_lw_capture_source + +static const struct snd_kcontrol_new alc269_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_AMP_FLAG, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc269_lifebook_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .subdevice = HDA_SUBDEV_AMP_FLAG, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT), + { } +}; + +static const struct snd_kcontrol_new alc269_laptop_mixer[] = { + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = { + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269_asus_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT), + { } /* end */ +}; + +/* capture mixer elements */ +static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +/* FSC amilo */ +#define alc269_fujitsu_mixer alc269_laptop_mixer + +static const struct hda_verb alc269_quanta_fl1_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + { } +}; + +static const struct hda_verb alc269_lifebook_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) +{ + alc_hp_automute(codec); + + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 0x0c); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x680); + + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 0x0c); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x480); +} + +#define alc269_lifebook_speaker_automute \ + alc269_quanta_fl1_speaker_automute + +static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) +{ + unsigned int present_laptop; + unsigned int present_dock; + + present_laptop = snd_hda_jack_detect(codec, 0x18); + present_dock = snd_hda_jack_detect(codec, 0x1b); + + /* Laptop mic port overrides dock mic port, design decision */ + if (present_dock) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x3); + if (present_laptop) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x0); + if (!present_dock && !present_laptop) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x1); +} + +static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC_HP_EVENT: + alc269_quanta_fl1_speaker_automute(codec); + break; + case ALC_MIC_EVENT: + alc_mic_automute(codec); + break; + } +} + +static void alc269_lifebook_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC_HP_EVENT) + alc269_lifebook_speaker_automute(codec); + if ((res >> 26) == ALC_MIC_EVENT) + alc269_lifebook_mic_autoswitch(codec); +} + +static void alc269_quanta_fl1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) +{ + alc269_quanta_fl1_speaker_automute(codec); + alc_mic_automute(codec); +} + +static void alc269_lifebook_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.hp_pins[1] = 0x1a; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; +} + +static void alc269_lifebook_init_hook(struct hda_codec *codec) +{ + alc269_lifebook_speaker_automute(codec); + alc269_lifebook_mic_autoswitch(codec); +} + +static const struct hda_verb alc269_laptop_dmic_init_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc269_laptop_amic_init_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x06}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = { + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc271_acer_dmic_verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x22, AC_VERB_SET_CONNECT_SEL, 6}, + { } +}; + +static void alc269_laptop_amic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +static void alc269_laptop_dmic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x12; + spec->auto_mic = 1; +} + +static void alc269vb_laptop_amic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x12; + spec->auto_mic = 1; +} + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc269_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* + * Set up output mixers (0x02 - 0x03) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* FIXME: use Mux-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* set EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc269vb_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* + * Set up output mixers (0x02 - 0x03) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* FIXME: use Mux-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x22, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* set EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +/* + * configuration and preset + */ +static const char * const alc269_models[ALC269_MODEL_LAST] = { + [ALC269_BASIC] = "basic", + [ALC269_QUANTA_FL1] = "quanta", + [ALC269_AMIC] = "laptop-amic", + [ALC269_DMIC] = "laptop-dmic", + [ALC269_FUJITSU] = "fujitsu", + [ALC269_LIFEBOOK] = "lifebook", + [ALC269_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc269_cfg_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), + SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER), + SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", + ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC), + SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", + ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", + ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC), + SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC), + SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO), + SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), + SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC), + SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), + SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC), + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC), + SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC), + SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC), + {} +}; + +static const struct alc_config_preset alc269_presets[] = { + [ALC269_BASIC] = { + .mixers = { alc269_base_mixer }, + .init_verbs = { alc269_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + }, + [ALC269_QUANTA_FL1] = { + .mixers = { alc269_quanta_fl1_mixer }, + .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .unsol_event = alc269_quanta_fl1_unsol_event, + .setup = alc269_quanta_fl1_setup, + .init_hook = alc269_quanta_fl1_init_hook, + }, + [ALC269_AMIC] = { + .mixers = { alc269_laptop_mixer }, + .cap_mixer = alc269_laptop_analog_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_laptop_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269_laptop_amic_setup, + .init_hook = alc_inithook, + }, + [ALC269_DMIC] = { + .mixers = { alc269_laptop_mixer }, + .cap_mixer = alc269_laptop_digital_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_laptop_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269_laptop_dmic_setup, + .init_hook = alc_inithook, + }, + [ALC269VB_AMIC] = { + .mixers = { alc269vb_laptop_mixer }, + .cap_mixer = alc269vb_laptop_analog_capture_mixer, + .init_verbs = { alc269vb_init_verbs, + alc269vb_laptop_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269vb_laptop_amic_setup, + .init_hook = alc_inithook, + }, + [ALC269VB_DMIC] = { + .mixers = { alc269vb_laptop_mixer }, + .cap_mixer = alc269vb_laptop_digital_capture_mixer, + .init_verbs = { alc269vb_init_verbs, + alc269vb_laptop_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269vb_laptop_dmic_setup, + .init_hook = alc_inithook, + }, + [ALC269_FUJITSU] = { + .mixers = { alc269_fujitsu_mixer }, + .cap_mixer = alc269_laptop_digital_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_laptop_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc269_laptop_dmic_setup, + .init_hook = alc_inithook, + }, + [ALC269_LIFEBOOK] = { + .mixers = { alc269_lifebook_mixer }, + .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .unsol_event = alc269_lifebook_unsol_event, + .setup = alc269_lifebook_setup, + .init_hook = alc269_lifebook_init_hook, + }, + [ALC271_ACER] = { + .mixers = { alc269_asus_mixer }, + .cap_mixer = alc269vb_laptop_digital_capture_mixer, + .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .adc_nids = alc262_dmic_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids), + .capsrc_nids = alc262_dmic_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .dig_out_nid = ALC880_DIGOUT_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc269vb_laptop_dmic_setup, + .init_hook = alc_inithook, + }, +}; + diff --git a/trunk/sound/pci/hda/alc662_quirks.c b/trunk/sound/pci/hda/alc662_quirks.c new file mode 100644 index 000000000000..e69a6ea3083a --- /dev/null +++ b/trunk/sound/pci/hda/alc662_quirks.c @@ -0,0 +1,1408 @@ +/* + * ALC662/ALC663/ALC665/ALC670 quirk models + * included by patch_realtek.c + */ + +/* ALC662 models */ +enum { + ALC662_AUTO, + ALC662_3ST_2ch_DIG, + ALC662_3ST_6ch_DIG, + ALC662_3ST_6ch, + ALC662_5ST_DIG, + ALC662_LENOVO_101E, + ALC662_ASUS_EEEPC_P701, + ALC662_ASUS_EEEPC_EP20, + ALC663_ASUS_M51VA, + ALC663_ASUS_G71V, + ALC663_ASUS_H13, + ALC663_ASUS_G50V, + ALC662_ECS, + ALC663_ASUS_MODE1, + ALC662_ASUS_MODE2, + ALC663_ASUS_MODE3, + ALC663_ASUS_MODE4, + ALC663_ASUS_MODE5, + ALC663_ASUS_MODE6, + ALC663_ASUS_MODE7, + ALC663_ASUS_MODE8, + ALC272_DELL, + ALC272_DELL_ZM1, + ALC272_SAMSUNG_NC10, + ALC662_MODEL_LAST, +}; + +#define ALC662_DIGOUT_NID 0x06 +#define ALC662_DIGIN_NID 0x0a + +static const hda_nid_t alc662_dac_nids[3] = { + /* front, rear, clfe */ + 0x02, 0x03, 0x04 +}; + +static const hda_nid_t alc272_dac_nids[2] = { + 0x02, 0x03 +}; + +static const hda_nid_t alc662_adc_nids[2] = { + /* ADC1-2 */ + 0x09, 0x08 +}; + +static const hda_nid_t alc272_adc_nids[1] = { + /* ADC1-2 */ + 0x08, +}; + +static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; +static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; + + +/* input MUX */ +/* FIXME: should be a matrix-type input source selection */ +static const struct hda_input_mux alc662_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc662_lenovo_101e_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; + +static const struct hda_input_mux alc663_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; + +#if 0 /* set to 1 for testing other input sources below */ +static const struct hda_input_mux alc272_nc10_capture_source = { + .num_items = 16, + .items = { + { "Autoselect Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "In-0x02", 0x2 }, + { "In-0x03", 0x3 }, + { "In-0x04", 0x4 }, + { "In-0x05", 0x5 }, + { "In-0x06", 0x6 }, + { "In-0x07", 0x7 }, + { "In-0x08", 0x8 }, + { "In-0x09", 0x9 }, + { "In-0x0a", 0x0a }, + { "In-0x0b", 0x0b }, + { "In-0x0c", 0x0c }, + { "In-0x0d", 0x0d }, + { "In-0x0e", 0x0e }, + { "In-0x0f", 0x0f }, + }, +}; +#endif + +/* + * 2ch mode + */ +static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = { + { 2, NULL } +}; + +/* + * 2ch mode + */ +static const struct hda_verb alc662_3ST_ch2_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc662_3ST_ch6_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = { + { 2, alc662_3ST_ch2_init }, + { 6, alc662_3ST_ch6_init }, +}; + +/* + * 2ch mode + */ +static const struct hda_verb alc662_sixstack_ch6_init[] = { + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc662_sixstack_ch8_init[] = { + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +static const struct hda_channel_mode alc662_5stack_modes[2] = { + { 2, alc662_sixstack_ch6_init }, + { 6, alc662_sixstack_ch8_init }, +}; + +/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 + * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b + */ + +static const struct snd_kcontrol_new alc662_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + /*Input mixer control */ + HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc663_asus_one_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_m51va_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_tree_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_four_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc662_1bjd_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc663_asus_two_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", + &alc663_asus_two_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { + HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_g71v_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_g50v_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc663_mode7_mixer[] = { + HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), + HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), + HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc663_mode8_mixer[] = { + HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), + HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), + HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + + +static const struct snd_kcontrol_new alc662_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc662_init_verbs[] = { + /* ADC: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Rear Pin: output 1 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + { } +}; + +static const struct hda_verb alc662_eapd_init_verbs[] = { + /* always trun on EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc662_sue_init_verbs[] = { + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_FRONT_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc662_eeepc_sue_init_verbs[] = { + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +/* Set Unsolicited Event*/ +static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc663_m51va_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc663_21jd_amic_init_verbs[] = { + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc662_1bjd_amic_init_verbs[] = { + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc663_15jd_amic_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc663_g71v_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ + /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ + + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ + + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_FRONT_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc663_g50v_init_verbs[] = { + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ + + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc662_ecs_init_verbs[] = { + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc272_dell_zm1_init_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc272_dell_init_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc663_mode7_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct hda_verb alc663_mode8_init_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { } /* end */ +}; + +static void alc662_lenovo_101e_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc662_eeepc_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + alc262_hippo1_setup(codec); + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +static void alc662_eeepc_ep20_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc663_m51va_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x12; + spec->auto_mic = 1; +} + +/* ***************** Mode1 ******************************/ +static void alc663_mode1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +/* ***************** Mode2 ******************************/ +static void alc662_mode2_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +/* ***************** Mode3 ******************************/ +static void alc663_mode3_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +/* ***************** Mode4 ******************************/ +static void alc663_mode4_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute_mixer_nid[1] = 0x0e; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +/* ***************** Mode5 ******************************/ +static void alc663_mode5_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute_mixer_nid[1] = 0x0e; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +/* ***************** Mode6 ******************************/ +static void alc663_mode6_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +/* ***************** Mode7 ******************************/ +static void alc663_mode7_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x19; + spec->auto_mic = 1; +} + +/* ***************** Mode8 ******************************/ +static void alc663_mode8_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.hp_pins[1] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x12; + spec->auto_mic = 1; +} + +static void alc663_g71v_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.line_out_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->ext_mic_pin = 0x18; + spec->int_mic_pin = 0x12; + spec->auto_mic = 1; +} + +#define alc663_g50v_setup alc663_m51va_setup + +static const struct snd_kcontrol_new alc662_ecs_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + + HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc272_nc10_mixer[] = { + /* Master Playback automatically created from Speaker and Headphone */ + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + + +/* + * configuration and preset + */ +static const char * const alc662_models[ALC662_MODEL_LAST] = { + [ALC662_3ST_2ch_DIG] = "3stack-dig", + [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", + [ALC662_3ST_6ch] = "3stack-6ch", + [ALC662_5ST_DIG] = "5stack-dig", + [ALC662_LENOVO_101E] = "lenovo-101e", + [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", + [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", + [ALC662_ECS] = "ecs", + [ALC663_ASUS_M51VA] = "m51va", + [ALC663_ASUS_G71V] = "g71v", + [ALC663_ASUS_H13] = "h13", + [ALC663_ASUS_G50V] = "g50v", + [ALC663_ASUS_MODE1] = "asus-mode1", + [ALC662_ASUS_MODE2] = "asus-mode2", + [ALC663_ASUS_MODE3] = "asus-mode3", + [ALC663_ASUS_MODE4] = "asus-mode4", + [ALC663_ASUS_MODE5] = "asus-mode5", + [ALC663_ASUS_MODE6] = "asus-mode6", + [ALC663_ASUS_MODE7] = "asus-mode7", + [ALC663_ASUS_MODE8] = "asus-mode8", + [ALC272_DELL] = "dell", + [ALC272_DELL_ZM1] = "dell-zm1", + [ALC272_SAMSUNG_NC10] = "samsung-nc10", + [ALC662_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc662_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), + SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL), + SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), + SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7), + SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7), + SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8), + SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA), + SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5), + SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), + /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/ + SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V), + /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/ + SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA), + SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4), + SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), + SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), + SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), + SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO), + SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13), + SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), + SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), + SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x", + ALC663_ASUS_H13), + SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E), + {} +}; + +static const struct alc_config_preset alc662_presets[] = { + [ALC662_3ST_2ch_DIG] = { + .mixers = { alc662_3ST_2ch_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .dig_in_nid = ALC662_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_capture_source, + }, + [ALC662_3ST_6ch_DIG] = { + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .dig_in_nid = ALC662_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc662_capture_source, + }, + [ALC662_3ST_6ch] = { + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc662_capture_source, + }, + [ALC662_5ST_DIG] = { + .mixers = { alc662_base_mixer, alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .dig_in_nid = ALC662_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes), + .channel_mode = alc662_5stack_modes, + .input_mux = &alc662_capture_source, + }, + [ALC662_LENOVO_101E] = { + .mixers = { alc662_lenovo_101e_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_lenovo_101e_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_lenovo_101e_setup, + .init_hook = alc_inithook, + }, + [ALC662_ASUS_EEEPC_P701] = { + .mixers = { alc662_eeepc_p701_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_eeepc_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_eeepc_setup, + .init_hook = alc_inithook, + }, + [ALC662_ASUS_EEEPC_EP20] = { + .mixers = { alc662_eeepc_ep20_mixer, + alc662_chmode_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_eeepc_ep20_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .input_mux = &alc662_lenovo_101e_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_eeepc_ep20_setup, + .init_hook = alc_inithook, + }, + [ALC662_ECS] = { + .mixers = { alc662_ecs_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_ecs_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_eeepc_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_M51VA] = { + .mixers = { alc663_m51va_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_m51va_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_G71V] = { + .mixers = { alc663_g71v_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g71v_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_g71v_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_H13] = { + .mixers = { alc663_m51va_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .setup = alc663_m51va_setup, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_G50V] = { + .mixers = { alc663_g50v_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g50v_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), + .channel_mode = alc662_3ST_6ch_modes, + .input_mux = &alc663_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_g50v_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE1] = { + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_21jd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode1_setup, + .init_hook = alc_inithook, + }, + [ALC662_ASUS_MODE2] = { + .mixers = { alc662_1bjd_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_1bjd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_mode2_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE3] = { + .mixers = { alc663_two_hp_m1_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_two_hp_amic_m1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode3_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE4] = { + .mixers = { alc663_asus_21jd_clfe_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_21jd_amic_init_verbs}, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode4_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE5] = { + .mixers = { alc663_asus_15jd_clfe_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_15jd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode5_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE6] = { + .mixers = { alc663_two_hp_m2_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_two_hp_amic_m2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode6_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE7] = { + .mixers = { alc663_mode7_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_mode7_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode7_setup, + .init_hook = alc_inithook, + }, + [ALC663_ASUS_MODE8] = { + .mixers = { alc663_mode8_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_mode8_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode8_setup, + .init_hook = alc_inithook, + }, + [ALC272_DELL] = { + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc272_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_init_verbs }, + .num_dacs = ARRAY_SIZE(alc272_dac_nids), + .dac_nids = alc272_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .adc_nids = alc272_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), + .capsrc_nids = alc272_capsrc_nids, + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_m51va_setup, + .init_hook = alc_inithook, + }, + [ALC272_DELL_ZM1] = { + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_zm1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc272_dac_nids), + .dac_nids = alc272_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .adc_nids = alc662_adc_nids, + .num_adc_nids = 1, + .capsrc_nids = alc662_capsrc_nids, + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc_sku_unsol_event, + .setup = alc663_m51va_setup, + .init_hook = alc_inithook, + }, + [ALC272_SAMSUNG_NC10] = { + .mixers = { alc272_nc10_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_21jd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc272_dac_nids), + .dac_nids = alc272_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + /*.input_mux = &alc272_nc10_capture_source,*/ + .unsol_event = alc_sku_unsol_event, + .setup = alc663_mode4_setup, + .init_hook = alc_inithook, + }, +}; + + diff --git a/trunk/sound/pci/hda/alc680_quirks.c b/trunk/sound/pci/hda/alc680_quirks.c new file mode 100644 index 000000000000..0eeb227c7bc2 --- /dev/null +++ b/trunk/sound/pci/hda/alc680_quirks.c @@ -0,0 +1,222 @@ +/* + * ALC680 quirk models + * included by patch_realtek.c + */ + +/* ALC680 models */ +enum { + ALC680_AUTO, + ALC680_BASE, + ALC680_MODEL_LAST, +}; + +#define ALC680_DIGIN_NID ALC880_DIGIN_NID +#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID +#define alc680_modes alc260_modes + +static const hda_nid_t alc680_dac_nids[3] = { + /* Lout1, Lout2, hp */ + 0x02, 0x03, 0x04 +}; + +static const hda_nid_t alc680_adc_nids[3] = { + /* ADC0-2 */ + /* DMIC, MIC, Line-in*/ + 0x07, 0x08, 0x09 +}; + +/* + * Analog capture ADC cgange + */ +static hda_nid_t alc680_get_cur_adc(struct hda_codec *codec) +{ + static hda_nid_t pins[] = {0x18, 0x19}; + static hda_nid_t adcs[] = {0x08, 0x09}; + int i; + + for (i = 0; i < ARRAY_SIZE(pins); i++) { + if (!is_jack_detectable(codec, pins[i])) + continue; + if (snd_hda_jack_detect(codec, pins[i])) + return adcs[i]; + } + return 0x07; +} + +static void alc680_rec_autoswitch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid = alc680_get_cur_adc(codec); + if (spec->cur_adc && nid != spec->cur_adc) { + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); + spec->cur_adc = nid; + snd_hda_codec_setup_stream(codec, nid, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + } +} + +static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid = alc680_get_cur_adc(codec); + + spec->cur_adc = nid; + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); + return 0; +} + +static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + snd_hda_codec_cleanup_stream(codec, spec->cur_adc); + spec->cur_adc = 0; + return 0; +} + +static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = { + .substreams = 1, /* can be overridden */ + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ + .ops = { + .prepare = alc680_capture_pcm_prepare, + .cleanup = alc680_capture_pcm_cleanup + }, +}; + +static const struct snd_kcontrol_new alc680_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT), + { } +}; + +static const struct hda_bind_ctls alc680_bind_cap_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static const struct hda_bind_ctls alc680_bind_cap_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static const struct snd_kcontrol_new alc680_master_capture_mixer[] = { + HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), + HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), + { } /* end */ +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc680_init_verbs[] = { + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, + + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc680_base_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x16; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.num_inputs = 2; + spec->autocfg.inputs[0].pin = 0x18; + spec->autocfg.inputs[0].type = AUTO_PIN_MIC; + spec->autocfg.inputs[1].pin = 0x19; + spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc680_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC_HP_EVENT) + alc_hp_automute(codec); + if ((res >> 26) == ALC_MIC_EVENT) + alc680_rec_autoswitch(codec); +} + +static void alc680_inithook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc680_rec_autoswitch(codec); +} + +/* + * configuration and preset + */ +static const char * const alc680_models[ALC680_MODEL_LAST] = { + [ALC680_BASE] = "base", + [ALC680_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc680_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), + {} +}; + +static const struct alc_config_preset alc680_presets[] = { + [ALC680_BASE] = { + .mixers = { alc680_base_mixer }, + .cap_mixer = alc680_master_capture_mixer, + .init_verbs = { alc680_init_verbs }, + .num_dacs = ARRAY_SIZE(alc680_dac_nids), + .dac_nids = alc680_dac_nids, + .dig_out_nid = ALC680_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc680_modes), + .channel_mode = alc680_modes, + .unsol_event = alc680_unsol_event, + .setup = alc680_base_setup, + .init_hook = alc680_inithook, + + }, +}; diff --git a/trunk/sound/pci/hda/alc861_quirks.c b/trunk/sound/pci/hda/alc861_quirks.c new file mode 100644 index 000000000000..d719ec6350eb --- /dev/null +++ b/trunk/sound/pci/hda/alc861_quirks.c @@ -0,0 +1,725 @@ +/* + * ALC660/ALC861 quirk models + * included by patch_realtek.c + */ + +/* ALC861 models */ +enum { + ALC861_AUTO, + ALC861_3ST, + ALC660_3ST, + ALC861_3ST_DIG, + ALC861_6ST_DIG, + ALC861_UNIWILL_M31, + ALC861_TOSHIBA, + ALC861_ASUS, + ALC861_ASUS_LAPTOP, + ALC861_MODEL_LAST, +}; + +/* + * ALC861 channel source setting (2/6 channel selection for 3-stack) + */ + +/* + * set the path ways for 2 channel output + * need to set the codec line out and mic 1 pin widgets to inputs + */ +static const struct hda_verb alc861_threestack_ch2_init[] = { + /* set pin widget 1Ah (line in) for input */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* set pin widget 18h (mic1/2) for input, for mic also enable + * the vref + */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ +#endif + { } /* end */ +}; +/* + * 6ch mode + * need to set the codec line out and mic 1 pin widgets to outputs + */ +static const struct hda_verb alc861_threestack_ch6_init[] = { + /* set pin widget 1Ah (line in) for output (Back Surround)*/ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* set pin widget 18h (mic1) for output (CLFE)*/ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + + { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, + + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ +#endif + { } /* end */ +}; + +static const struct hda_channel_mode alc861_threestack_modes[2] = { + { 2, alc861_threestack_ch2_init }, + { 6, alc861_threestack_ch6_init }, +}; +/* Set mic1 as input and unmute the mixer */ +static const struct hda_verb alc861_uniwill_m31_ch2_init[] = { + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ + { } /* end */ +}; +/* Set mic1 as output and mute mixer */ +static const struct hda_verb alc861_uniwill_m31_ch4_init[] = { + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ + { } /* end */ +}; + +static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = { + { 2, alc861_uniwill_m31_ch2_init }, + { 4, alc861_uniwill_m31_ch4_init }, +}; + +/* Set mic1 and line-in as input and unmute the mixer */ +static const struct hda_verb alc861_asus_ch2_init[] = { + /* set pin widget 1Ah (line in) for input */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* set pin widget 18h (mic1/2) for input, for mic also enable + * the vref + */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ +#endif + { } /* end */ +}; +/* Set mic1 nad line-in as output and mute mixer */ +static const struct hda_verb alc861_asus_ch6_init[] = { + /* set pin widget 1Ah (line in) for output (Back Surround)*/ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ + /* set pin widget 18h (mic1) for output (CLFE)*/ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ + { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, + + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ +#endif + { } /* end */ +}; + +static const struct hda_channel_mode alc861_asus_modes[2] = { + { 2, alc861_asus_ch2_init }, + { 6, alc861_asus_ch6_init }, +}; + +/* patch-ALC861 */ + +static const struct snd_kcontrol_new alc861_base_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), + + /*Input mixer control */ + /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), + + { } /* end */ +}; + +static const struct snd_kcontrol_new alc861_3ST_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ + + /* Input mixer control */ + /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), + + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + .private_value = ARRAY_SIZE(alc861_threestack_modes), + }, + { } /* end */ +}; + +static const struct snd_kcontrol_new alc861_toshiba_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + + { } /* end */ +}; + +static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ + + /* Input mixer control */ + /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), + + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes), + }, + { } /* end */ +}; + +static const struct snd_kcontrol_new alc861_asus_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), + + /* Input mixer control */ + HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), + + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + .private_value = ARRAY_SIZE(alc861_asus_modes), + }, + { } +}; + +/* additional mixer */ +static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + { } +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc861_base_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + + { } +}; + +static const struct hda_verb alc861_threestack_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + { } +}; + +static const struct hda_verb alc861_uniwill_m31_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + /* this has to be set to VREF80 */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + { } +}; + +static const struct hda_verb alc861_asus_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) + * according to codec#0 this is the HP jack + */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */ + /* route front PCM to HP */ + { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + /* this has to be set to VREF80 */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + { } +}; + +/* additional init verbs for ASUS laptops */ +static const struct hda_verb alc861_asus_laptop_init_verbs[] = { + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */ + { } +}; + +static const struct hda_verb alc861_toshiba_init_verbs[] = { + {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc861_toshiba_automute(struct hda_codec *codec) +{ + unsigned int present = snd_hda_jack_detect(codec, 0x0f); + + snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); +} + +static void alc861_toshiba_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC_HP_EVENT) + alc861_toshiba_automute(codec); +} + +#define ALC861_DIGOUT_NID 0x07 + +static const struct hda_channel_mode alc861_8ch_modes[1] = { + { 8, NULL } +}; + +static const hda_nid_t alc861_dac_nids[4] = { + /* front, surround, clfe, side */ + 0x03, 0x06, 0x05, 0x04 +}; + +static const hda_nid_t alc660_dac_nids[3] = { + /* front, clfe, surround */ + 0x03, 0x05, 0x06 +}; + +static const hda_nid_t alc861_adc_nids[1] = { + /* ADC0-2 */ + 0x08, +}; + +static const struct hda_input_mux alc861_capture_source = { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x3 }, + { "Line", 0x1 }, + { "CD", 0x4 }, + { "Mixer", 0x5 }, + }, +}; + +/* + * configuration and preset + */ +static const char * const alc861_models[ALC861_MODEL_LAST] = { + [ALC861_3ST] = "3stack", + [ALC660_3ST] = "3stack-660", + [ALC861_3ST_DIG] = "3stack-dig", + [ALC861_6ST_DIG] = "6stack-dig", + [ALC861_UNIWILL_M31] = "uniwill-m31", + [ALC861_TOSHIBA] = "toshiba", + [ALC861_ASUS] = "asus", + [ALC861_ASUS_LAPTOP] = "asus-laptop", + [ALC861_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc861_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), + SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), + SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG), + SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), + /* FIXME: the entry below breaks Toshiba A100 (model=auto works!) + * Any other models that need this preset? + */ + /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */ + SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST), + SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST), + SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), + SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), + SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP), + /* FIXME: the below seems conflict */ + /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */ + SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), + SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), + {} +}; + +static const struct alc_config_preset alc861_presets[] = { + [ALC861_3ST] = { + .mixers = { alc861_3ST_mixer }, + .init_verbs = { alc861_threestack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), + .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_3ST_DIG] = { + .mixers = { alc861_base_mixer }, + .init_verbs = { alc861_threestack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), + .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_6ST_DIG] = { + .mixers = { alc861_base_mixer }, + .init_verbs = { alc861_base_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes), + .channel_mode = alc861_8ch_modes, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC660_3ST] = { + .mixers = { alc861_3ST_mixer }, + .init_verbs = { alc861_threestack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc660_dac_nids), + .dac_nids = alc660_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), + .channel_mode = alc861_threestack_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_UNIWILL_M31] = { + .mixers = { alc861_uniwill_m31_mixer }, + .init_verbs = { alc861_uniwill_m31_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes), + .channel_mode = alc861_uniwill_m31_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_TOSHIBA] = { + .mixers = { alc861_toshiba_mixer }, + .init_verbs = { alc861_base_init_verbs, + alc861_toshiba_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + .unsol_event = alc861_toshiba_unsol_event, + .init_hook = alc861_toshiba_automute, + }, + [ALC861_ASUS] = { + .mixers = { alc861_asus_mixer }, + .init_verbs = { alc861_asus_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_asus_modes), + .channel_mode = alc861_asus_modes, + .need_dac_fix = 1, + .hp_nid = 0x06, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, + [ALC861_ASUS_LAPTOP] = { + .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer }, + .init_verbs = { alc861_asus_init_verbs, + alc861_asus_laptop_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, +}; + diff --git a/trunk/sound/pci/hda/alc861vd_quirks.c b/trunk/sound/pci/hda/alc861vd_quirks.c new file mode 100644 index 000000000000..8f28450f41f8 --- /dev/null +++ b/trunk/sound/pci/hda/alc861vd_quirks.c @@ -0,0 +1,605 @@ +/* + * ALC660-VD/ALC861-VD quirk models + * included by patch_realtek.c + */ + +/* ALC861-VD models */ +enum { + ALC861VD_AUTO, + ALC660VD_3ST, + ALC660VD_3ST_DIG, + ALC660VD_ASUS_V1S, + ALC861VD_3ST, + ALC861VD_3ST_DIG, + ALC861VD_6ST_DIG, + ALC861VD_LENOVO, + ALC861VD_DALLAS, + ALC861VD_HP, + ALC861VD_MODEL_LAST, +}; + +#define ALC861VD_DIGOUT_NID 0x06 + +static const hda_nid_t alc861vd_dac_nids[4] = { + /* front, surr, clfe, side surr */ + 0x02, 0x03, 0x04, 0x05 +}; + +/* dac_nids for ALC660vd are in a different order - according to + * Realtek's driver. + * This should probably result in a different mixer for 6stack models + * of ALC660vd codecs, but for now there is only 3stack mixer + * - and it is the same as in 861vd. + * adc_nids in ALC660vd are (is) the same as in 861vd + */ +static const hda_nid_t alc660vd_dac_nids[3] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x04, 0x03 +}; + +static const hda_nid_t alc861vd_adc_nids[1] = { + /* ADC0 */ + 0x09, +}; + +static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 }; + +/* input MUX */ +/* FIXME: should be a matrix-type input source selection */ +static const struct hda_input_mux alc861vd_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc861vd_dallas_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + }, +}; + +static const struct hda_input_mux alc861vd_hp_capture_source = { + .num_items = 2, + .items = { + { "Front Mic", 0x0 }, + { "ATAPI Mic", 0x1 }, + }, +}; + +/* + * 2ch mode + */ +static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { + { 2, NULL } +}; + +/* + * 6ch mode + */ +static const struct hda_verb alc861vd_6stack_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static const struct hda_verb alc861vd_6stack_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +static const struct hda_channel_mode alc861vd_6stack_modes[2] = { + { 6, alc861vd_6stack_ch6_init }, + { 8, alc861vd_6stack_ch8_init }, +}; + +static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 + * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b + */ +static const struct snd_kcontrol_new alc861vd_6st_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + + HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + { } /* end */ +}; + +static const struct snd_kcontrol_new alc861vd_3st_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + { } /* end */ +}; + +static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/ + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + { } /* end */ +}; + +/* Pin assignment: Speaker=0x14, HP = 0x15, + * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d + */ +static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +/* Pin assignment: Speaker=0x14, Line-out = 0x15, + * Front Mic=0x18, ATAPI Mic = 0x19, + */ +static const struct snd_kcontrol_new alc861vd_hp_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + { } /* end */ +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc861vd_volume_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of + * the analog-loopback mixer widget + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output mixers (0x02 - 0x05) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +/* + * 3-stack pin configuration: + * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b + */ +static const struct hda_verb alc861vd_3stack_init_verbs[] = { + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * 6-stack pin configuration: + */ +static const struct hda_verb alc861vd_6stack_init_verbs[] = { + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Rear Pin: output 1 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* Side Pin: output 3 (0x0f) */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +static const struct hda_verb alc861vd_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + {} +}; + +static void alc861vd_lenovo_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +static void alc861vd_lenovo_init_hook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc88x_simple_mic_automute(codec); +} + +static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC_MIC_EVENT: + alc88x_simple_mic_automute(codec); + break; + default: + alc_sku_unsol_event(codec, res); + break; + } +} + +static const struct hda_verb alc861vd_dallas_verbs[] = { + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + + { } /* end */ +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc861vd_dallas_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; +} + +/* + * configuration and preset + */ +static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = { + [ALC660VD_3ST] = "3stack-660", + [ALC660VD_3ST_DIG] = "3stack-660-digout", + [ALC660VD_ASUS_V1S] = "asus-v1s", + [ALC861VD_3ST] = "3stack", + [ALC861VD_3ST_DIG] = "3stack-digout", + [ALC861VD_6ST_DIG] = "6stack-digout", + [ALC861VD_LENOVO] = "lenovo", + [ALC861VD_DALLAS] = "dallas", + [ALC861VD_HP] = "hp", + [ALC861VD_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc861vd_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), + SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), + SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), + /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */ + SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S), + SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), + SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), + SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), + /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ + SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS), + SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), + {} +}; + +static const struct alc_config_preset alc861vd_presets[] = { + [ALC660VD_3ST] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC660VD_3ST_DIG] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_3ST] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_3ST_DIG] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_6ST_DIG] = { + .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_6stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes), + .channel_mode = alc861vd_6stack_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_LENOVO] = { + .mixers = { alc861vd_lenovo_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs, + alc861vd_eapd_verbs, + alc861vd_lenovo_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + .unsol_event = alc861vd_lenovo_unsol_event, + .setup = alc861vd_lenovo_setup, + .init_hook = alc861vd_lenovo_init_hook, + }, + [ALC861VD_DALLAS] = { + .mixers = { alc861vd_dallas_mixer }, + .init_verbs = { alc861vd_dallas_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_dallas_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc861vd_dallas_setup, + .init_hook = alc_hp_automute, + }, + [ALC861VD_HP] = { + .mixers = { alc861vd_hp_mixer }, + .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_hp_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc861vd_dallas_setup, + .init_hook = alc_hp_automute, + }, + [ALC660VD_ASUS_V1S] = { + .mixers = { alc861vd_lenovo_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs, + alc861vd_eapd_verbs, + alc861vd_lenovo_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + .unsol_event = alc861vd_lenovo_unsol_event, + .setup = alc861vd_lenovo_setup, + .init_hook = alc861vd_lenovo_init_hook, + }, +}; + diff --git a/trunk/sound/pci/hda/alc880_quirks.c b/trunk/sound/pci/hda/alc880_quirks.c index bea22edcfd8c..c844d2b59988 100644 --- a/trunk/sound/pci/hda/alc880_quirks.c +++ b/trunk/sound/pci/hda/alc880_quirks.c @@ -749,7 +749,8 @@ static void alc880_uniwill_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x16; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc880_uniwill_init_hook(struct hda_codec *codec) @@ -780,7 +781,8 @@ static void alc880_uniwill_p53_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -1049,7 +1051,8 @@ static void alc880_lg_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x17; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* @@ -1134,7 +1137,8 @@ static void alc880_lg_lw_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = { @@ -1184,7 +1188,7 @@ static void alc880_medion_rim_automute(struct hda_codec *codec) struct alc_spec *spec = codec->spec; alc_hp_automute(codec); /* toggle EAPD */ - if (spec->hp_jack_present) + if (spec->jack_present) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); else snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2); @@ -1206,7 +1210,8 @@ static void alc880_medion_rim_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } #ifdef CONFIG_SND_HDA_POWER_SAVE diff --git a/trunk/sound/pci/hda/alc882_quirks.c b/trunk/sound/pci/hda/alc882_quirks.c index e251514a26a4..617d04723b82 100644 --- a/trunk/sound/pci/hda/alc882_quirks.c +++ b/trunk/sound/pci/hda/alc882_quirks.c @@ -173,7 +173,8 @@ static void alc889_automute_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x17; spec->autocfg.speaker_pins[3] = 0x19; spec->autocfg.speaker_pins[4] = 0x1a; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc889_intel_init_hook(struct hda_codec *codec) @@ -190,7 +191,8 @@ static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) spec->autocfg.hp_pins[1] = 0x1b; /* hp */ spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ spec->autocfg.speaker_pins[1] = 0x15; /* bass */ - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* @@ -473,7 +475,8 @@ static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) @@ -484,7 +487,8 @@ static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) @@ -495,7 +499,8 @@ static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) @@ -506,7 +511,8 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x1b; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } #define ALC882_DIGOUT_NID 0x06 @@ -1705,7 +1711,8 @@ static void alc885_imac24_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x18; spec->autocfg.speaker_pins[1] = 0x1a; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } #define alc885_mb5_setup alc885_imac24_setup @@ -1714,11 +1721,12 @@ static void alc885_imac24_setup(struct hda_codec *codec) /* Macbook Air 2,1 */ static void alc885_mba21_setup(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } @@ -1729,7 +1737,8 @@ static void alc885_mbp3_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc885_imac91_setup(struct hda_codec *codec) @@ -1739,7 +1748,8 @@ static void alc885_imac91_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x18; spec->autocfg.speaker_pins[1] = 0x1a; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static const struct hda_verb alc882_targa_verbs[] = { @@ -1763,7 +1773,7 @@ static void alc882_targa_automute(struct hda_codec *codec) struct alc_spec *spec = codec->spec; alc_hp_automute(codec); snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - spec->hp_jack_present ? 1 : 3); + spec->jack_present ? 1 : 3); } static void alc882_targa_setup(struct hda_codec *codec) @@ -1772,7 +1782,8 @@ static void alc882_targa_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) @@ -2176,7 +2187,8 @@ static void alc883_medion_wim2160_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1a; spec->autocfg.speaker_pins[0] = 0x15; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { @@ -2329,7 +2341,8 @@ static void alc883_mitac_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x17; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static const struct hda_verb alc883_mitac_verbs[] = { @@ -2494,7 +2507,8 @@ static void alc888_3st_hp_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x18; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static const struct hda_verb alc888_3st_hp_verbs[] = { @@ -2554,7 +2568,8 @@ static void alc888_lenovo_ms7195_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.line_out_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* toggle speaker-output according to the hp-jack state */ @@ -2564,7 +2579,8 @@ static void alc883_lenovo_nb0763_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* toggle speaker-output according to the hp-jack state */ @@ -2577,7 +2593,8 @@ static void alc883_clevo_m720_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc883_clevo_m720_init_hook(struct hda_codec *codec) @@ -2606,7 +2623,8 @@ static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc883_haier_w66_setup(struct hda_codec *codec) @@ -2615,7 +2633,8 @@ static void alc883_haier_w66_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc883_lenovo_101e_setup(struct hda_codec *codec) @@ -2625,7 +2644,10 @@ static void alc883_lenovo_101e_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.line_out_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* toggle speaker-output according to the hp-jack state */ @@ -2636,7 +2658,8 @@ static void alc883_acer_aspire_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; spec->autocfg.speaker_pins[1] = 0x16; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static const struct hda_verb alc883_acer_eapd_verbs[] = { @@ -2666,7 +2689,8 @@ static void alc888_6st_dell_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[1] = 0x15; spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[3] = 0x17; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc888_lenovo_sky_setup(struct hda_codec *codec) @@ -2679,7 +2703,8 @@ static void alc888_lenovo_sky_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[3] = 0x17; spec->autocfg.speaker_pins[4] = 0x1a; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc883_vaiott_setup(struct hda_codec *codec) @@ -2689,7 +2714,8 @@ static void alc883_vaiott_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x17; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static const struct hda_verb alc888_asus_m90v_verbs[] = { @@ -2713,7 +2739,8 @@ static void alc883_mode2_setup(struct hda_codec *codec) spec->ext_mic_pin = 0x18; spec->int_mic_pin = 0x19; spec->auto_mic = 1; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static const struct hda_verb alc888_asus_eee1601_verbs[] = { diff --git a/trunk/sound/pci/hda/alc_quirks.c b/trunk/sound/pci/hda/alc_quirks.c index a18952ed4311..2be1129cf458 100644 --- a/trunk/sound/pci/hda/alc_quirks.c +++ b/trunk/sound/pci/hda/alc_quirks.c @@ -453,19 +453,6 @@ static void setup_preset(struct hda_codec *codec, alc_fixup_autocfg_pin_nums(codec); } -static void alc_simple_setup_automute(struct alc_spec *spec, int mode) -{ - int lo_pin = spec->autocfg.line_out_pins[0]; - - if (lo_pin == spec->autocfg.speaker_pins[0] || - lo_pin == spec->autocfg.hp_pins[0]) - lo_pin = 0; - spec->automute_mode = mode; - spec->detect_hp = !!spec->autocfg.hp_pins[0]; - spec->detect_lo = !!lo_pin; - spec->automute_lo = spec->automute_lo_possible = !!lo_pin; - spec->automute_speaker = spec->automute_speaker_possible = !!spec->autocfg.speaker_pins[0]; -} /* auto-toggle front mic */ static void alc88x_simple_mic_automute(struct hda_codec *codec) diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index 1715e8b24ff0..3e7850c238c3 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -34,9 +34,6 @@ #include "hda_beep.h" #include -#define CREATE_TRACE_POINTS -#include "hda_trace.h" - /* * vendor / preset table */ @@ -211,19 +208,15 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, again: snd_hda_power_up(codec); mutex_lock(&bus->cmd_mutex); - trace_hda_send_cmd(codec, cmd); err = bus->ops.command(bus, cmd); - if (!err && res) { + if (!err && res) *res = bus->ops.get_response(bus, codec->addr); - trace_hda_get_response(codec, *res); - } mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); if (res && *res == -1 && bus->rirb_error) { if (bus->response_reset) { snd_printd("hda_codec: resetting BUS due to " "fatal communication error\n"); - trace_hda_bus_reset(bus); bus->ops.bus_reset(bus); } goto again; @@ -586,13 +579,9 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, return -1; } recursive++; - for (i = 0; i < nums; i++) { - unsigned int type = get_wcaps_type(get_wcaps(codec, conn[i])); - if (type == AC_WID_PIN || type == AC_WID_AUD_OUT) - continue; + for (i = 0; i < nums; i++) if (snd_hda_get_conn_index(codec, conn[i], nid, recursive) >= 0) return i; - } return -1; } EXPORT_SYMBOL_HDA(snd_hda_get_conn_index); @@ -614,7 +603,6 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) struct hda_bus_unsolicited *unsol; unsigned int wp; - trace_hda_unsol_event(bus, res, res_ex); unsol = bus->unsol; if (!unsol) return 0; @@ -1491,11 +1479,8 @@ static void really_cleanup_stream(struct hda_codec *codec, struct hda_cvt_setup *q) { hda_nid_t nid = q->nid; - if (q->stream_tag || q->channel_id) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); - if (q->format_id) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0 -); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); memset(q, 0, sizeof(*q)); q->nid = nid; } @@ -1699,29 +1684,6 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); -/** - * snd_hda_override_pin_caps - Override the pin capabilities - * @codec: the CODEC - * @nid: the NID to override - * @caps: the capability bits to set - * - * Override the cached PIN capabilitiy bits value by the given one. - * - * Returns zero if successful or a negative error code. - */ -int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, - unsigned int caps) -{ - struct hda_amp_info *info; - info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid)); - if (!info) - return -ENOMEM; - info->amp_caps = caps; - info->head.val |= INFO_AMP_CAPS; - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps); - /** * snd_hda_pin_sense - execute pin sense measurement * @codec: the CODEC to sense @@ -4121,7 +4083,6 @@ static void hda_power_work(struct work_struct *work) return; } - trace_hda_power_down(codec); hda_call_codec_suspend(codec); if (bus->ops.pm_notify) bus->ops.pm_notify(bus); @@ -4160,7 +4121,6 @@ void snd_hda_power_up(struct hda_codec *codec) if (codec->power_on || codec->power_transition) return; - trace_hda_power_up(codec); snd_hda_update_power_acct(codec); codec->power_on = 1; codec->power_jiffies = jiffies; @@ -4573,11 +4533,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); /* extra outputs copied from front */ - for (i = 0; i < ARRAY_SIZE(mout->hp_out_nid); i++) - if (!mout->no_share_stream && mout->hp_out_nid[i]) - snd_hda_codec_setup_stream(codec, - mout->hp_out_nid[i], - stream_tag, 0, format); for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) if (!mout->no_share_stream && mout->extra_out_nid[i]) snd_hda_codec_setup_stream(codec, @@ -4610,10 +4565,6 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, snd_hda_codec_cleanup_stream(codec, nids[i]); if (mout->hp_nid) snd_hda_codec_cleanup_stream(codec, mout->hp_nid); - for (i = 0; i < ARRAY_SIZE(mout->hp_out_nid); i++) - if (mout->hp_out_nid[i]) - snd_hda_codec_cleanup_stream(codec, - mout->hp_out_nid[i]); for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) if (mout->extra_out_nid[i]) snd_hda_codec_cleanup_stream(codec, @@ -4694,27 +4645,6 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) } } -/* Reorder the surround channels - * ALSA sequence is front/surr/clfe/side - * HDA sequence is: - * 4-ch: front/surr => OK as it is - * 6-ch: front/clfe/surr - * 8-ch: front/clfe/rear/side|fc - */ -static void reorder_outputs(unsigned int nums, hda_nid_t *pins) -{ - hda_nid_t nid; - - switch (nums) { - case 3: - case 4: - nid = pins[1]; - pins[1] = pins[2]; - pins[2] = nid; - break; - } -} - /* * Parse all pin widgets and store the useful pin nids to cfg * @@ -4732,13 +4662,12 @@ static void reorder_outputs(unsigned int nums, hda_nid_t *pins) * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. */ -int snd_hda_parse_pin_defcfg(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - const hda_nid_t *ignore_nids, - unsigned int cond_flags) +int snd_hda_parse_pin_def_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg, + const hda_nid_t *ignore_nids) { hda_nid_t nid, end_nid; - short seq, assoc_line_out; + short seq, assoc_line_out, assoc_speaker; short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; @@ -4749,7 +4678,7 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, memset(sequences_line_out, 0, sizeof(sequences_line_out)); memset(sequences_speaker, 0, sizeof(sequences_speaker)); memset(sequences_hp, 0, sizeof(sequences_hp)); - assoc_line_out = 0; + assoc_line_out = assoc_speaker = 0; end_nid = codec->start_nid + codec->num_nodes; for (nid = codec->start_nid; nid < end_nid; nid++) { @@ -4801,10 +4730,16 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, case AC_JACK_SPEAKER: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); + if (!assoc) + continue; + if (!assoc_speaker) + assoc_speaker = assoc; + else if (assoc_speaker != assoc) + continue; if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) continue; cfg->speaker_pins[cfg->speaker_outs] = nid; - sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; + sequences_speaker[cfg->speaker_outs] = seq; cfg->speaker_outs++; break; case AC_JACK_HP_OUT: @@ -4853,8 +4788,7 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, * If no line-out is defined but multiple HPs are found, * some of them might be the real line-outs. */ - if (!cfg->line_outs && cfg->hp_outs > 1 && - !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) { + if (!cfg->line_outs && cfg->hp_outs > 1) { int i = 0; while (i < cfg->hp_outs) { /* The real HPs should have the sequence 0x0f */ @@ -4891,8 +4825,7 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, * FIX-UP: if no line-outs are detected, try to use speaker or HP pin * as a primary output */ - if (!cfg->line_outs && - !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) { + if (!cfg->line_outs) { if (cfg->speaker_outs) { cfg->line_outs = cfg->speaker_outs; memcpy(cfg->line_out_pins, cfg->speaker_pins, @@ -4910,9 +4843,21 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, } } - reorder_outputs(cfg->line_outs, cfg->line_out_pins); - reorder_outputs(cfg->hp_outs, cfg->hp_pins); - reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); + /* Reorder the surround channels + * ALSA sequence is front/surr/clfe/side + * HDA sequence is: + * 4-ch: front/surr => OK as it is + * 6-ch: front/clfe/surr + * 8-ch: front/clfe/rear/side|fc + */ + switch (cfg->line_outs) { + case 3: + case 4: + nid = cfg->line_out_pins[1]; + cfg->line_out_pins[1] = cfg->line_out_pins[2]; + cfg->line_out_pins[2] = nid; + break; + } sort_autocfg_input_pins(cfg); @@ -4950,7 +4895,7 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, return 0; } -EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg); +EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config); int snd_hda_get_input_pin_attr(unsigned int def_conf) { @@ -5208,6 +5153,30 @@ void snd_array_free(struct snd_array *array) } EXPORT_SYMBOL_HDA(snd_array_free); +/** + * snd_print_pcm_rates - Print the supported PCM rates to the string buffer + * @pcm: PCM caps bits + * @buf: the string buffer to write + * @buflen: the max buffer length + * + * used by hda_proc.c and hda_eld.c + */ +void snd_print_pcm_rates(int pcm, char *buf, int buflen) +{ + static unsigned int rates[] = { + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, + 96000, 176400, 192000, 384000 + }; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++) + if (pcm & (1 << i)) + j += snprintf(buf + j, buflen - j, " %d", rates[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} +EXPORT_SYMBOL_HDA(snd_print_pcm_rates); + /** * snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer * @pcm: PCM caps bits @@ -5249,8 +5218,6 @@ static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid, return "Mic"; case SND_JACK_LINEOUT: return "Line-out"; - case SND_JACK_LINEIN: - return "Line-in"; case SND_JACK_HEADSET: return "Headset"; case SND_JACK_VIDEOOUT: diff --git a/trunk/sound/pci/hda/hda_eld.c b/trunk/sound/pci/hda/hda_eld.c index 1c8ddf547a2d..28ce17d09c33 100644 --- a/trunk/sound/pci/hda/hda_eld.c +++ b/trunk/sound/pci/hda/hda_eld.c @@ -144,17 +144,25 @@ static int cea_sampling_frequencies[8] = { SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ }; -static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, +static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid, int byte_index) { unsigned int val; val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD, byte_index); + #ifdef BE_PARANOID printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val); #endif - return val; + + if ((val & AC_ELDD_ELD_VALID) == 0) { + snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n", + byte_index); + val = 0; + } + + return val & AC_ELDD_ELD_DATA; } #define GRAB_BITS(buf, byte, lowbit, bits) \ @@ -318,11 +326,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, int size; unsigned char *buf; - /* - * ELD size is initialized to zero in caller function. If no errors and - * ELD is valid, actual eld_size is assigned in hdmi_update_eld() - */ - if (!eld->eld_valid) return -ENOENT; @@ -332,59 +335,24 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); size = 128; } - if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { + if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); return -ERANGE; } - /* set ELD buffer */ - buf = eld->eld_buffer; - - for (i = 0; i < size; i++) { - unsigned int val = hdmi_get_eld_data(codec, nid, i); - if (!(val & AC_ELDD_ELD_VALID)) { - if (!i) { - snd_printd(KERN_INFO - "HDMI: invalid ELD data\n"); - ret = -EINVAL; - goto error; - } - snd_printd(KERN_INFO - "HDMI: invalid ELD data byte %d\n", i); - val = 0; - } else - val &= AC_ELDD_ELD_DATA; - buf[i] = val; - } + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < size; i++) + buf[i] = hdmi_get_eld_byte(codec, nid, i); ret = hdmi_update_eld(eld, buf, size); -error: + kfree(buf); return ret; } -/** - * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with - * hdmi-specific routine. - */ -static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) -{ - static unsigned int alsa_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, - 96000, 176400, 192000, 384000 - }; - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++) - if (pcm & (1 << i)) - j += snprintf(buf + j, buflen - j, " %d", - alsa_rates[i]); - - buf[j] = '\0'; /* necessary when j == 0 */ -} - -#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 - static void hdmi_show_short_audio_desc(struct cea_sad *a) { char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; @@ -393,7 +361,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) if (!a->format) return; - hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); + snd_print_pcm_rates(a->rates, buf, sizeof(buf)); if (a->format == AUDIO_CODING_TYPE_LPCM) snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8); @@ -452,7 +420,7 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a, i, a->format, cea_audio_coding_type_names[a->format]); snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); - hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); + snd_print_pcm_rates(a->rates, buf, sizeof(buf)); snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); if (a->format == AUDIO_CODING_TYPE_LPCM) { diff --git a/trunk/sound/pci/hda/hda_hwdep.c b/trunk/sound/pci/hda/hda_hwdep.c index 7e7d0788ddcf..bf3ced51e0f8 100644 --- a/trunk/sound/pci/hda/hda_hwdep.c +++ b/trunk/sound/pci/hda/hda_hwdep.c @@ -643,14 +643,14 @@ static inline int strmatch(const char *a, const char *b) static void parse_codec_mode(char *buf, struct hda_bus *bus, struct hda_codec **codecp) { - int vendorid, subid, caddr; + unsigned int vendorid, subid, caddr; struct hda_codec *codec; *codecp = NULL; if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) { list_for_each_entry(codec, &bus->codec_list, list) { - if ((vendorid <= 0 || codec->vendor_id == vendorid) && - (subid <= 0 || codec->subsystem_id == subid) && + if (codec->vendor_id == vendorid && + codec->subsystem_id == subid && codec->addr == caddr) { *codecp = codec; break; @@ -756,6 +756,8 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw) } if (!fw->size) return 0; + if (size < fw->size) + size = fw->size; for (len = 0; len < fw->size; len++) { if (!*p) diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index bd7fc99af187..be6982289c0d 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -34,6 +34,7 @@ * */ +#include #include #include #include @@ -45,12 +46,6 @@ #include #include #include -#include -#ifdef CONFIG_X86 -/* for snoop control */ -#include -#include -#endif #include #include #include "hda_codec.h" @@ -121,22 +116,6 @@ module_param(power_save_controller, bool, 0644); MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); #endif -static int align_buffer_size = 1; -module_param(align_buffer_size, bool, 0644); -MODULE_PARM_DESC(align_buffer_size, - "Force buffer and period sizes to be multiple of 128 bytes."); - -#ifdef CONFIG_X86 -static bool hda_snoop = true; -module_param_named(snoop, hda_snoop, bool, 0444); -MODULE_PARM_DESC(snoop, "Enable/disable snooping"); -#define azx_snoop(chip) (chip)->snoop -#else -#define hda_snoop true -#define azx_snoop(chip) true -#endif - - MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH6M}," @@ -381,7 +360,7 @@ struct azx_dev { */ unsigned char stream_tag; /* assigned stream */ unsigned char index; /* stream index */ - int assigned_key; /* last device# key assigned to */ + int device; /* last device number assigned to */ unsigned int opened :1; unsigned int running :1; @@ -392,7 +371,6 @@ struct azx_dev { * when link position is not greater than FIFO size */ unsigned int insufficient :1; - unsigned int wc_marked:1; }; /* CORB/RIRB */ @@ -460,7 +438,6 @@ struct azx { unsigned int msi :1; unsigned int irq_pending_warned :1; unsigned int probing :1; /* codec probing phase */ - unsigned int snoop:1; /* for debugging */ unsigned int last_cmd[AZX_MAX_CODECS]; @@ -504,7 +481,6 @@ enum { #define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ #define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ #define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ -#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -566,45 +542,6 @@ static char *driver_short_names[] __devinitdata = { /* for pcm support */ #define get_azx_dev(substream) (substream->runtime->private_data) -#ifdef CONFIG_X86 -static void __mark_pages_wc(struct azx *chip, void *addr, size_t size, bool on) -{ - if (azx_snoop(chip)) - return; - if (addr && size) { - int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (on) - set_memory_wc((unsigned long)addr, pages); - else - set_memory_wb((unsigned long)addr, pages); - } -} - -static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, - bool on) -{ - __mark_pages_wc(chip, buf->area, buf->bytes, on); -} -static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, - struct snd_pcm_runtime *runtime, bool on) -{ - if (azx_dev->wc_marked != on) { - __mark_pages_wc(chip, runtime->dma_area, runtime->dma_bytes, on); - azx_dev->wc_marked = on; - } -} -#else -/* NOP for other archs */ -static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, - bool on) -{ -} -static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, - struct snd_pcm_runtime *runtime, bool on) -{ -} -#endif - static int azx_acquire_irq(struct azx *chip, int do_disconnect); static int azx_send_cmd(struct hda_bus *bus, unsigned int val); /* @@ -626,7 +563,6 @@ static int azx_alloc_cmd_io(struct azx *chip) snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n"); return err; } - mark_pages_wc(chip, &chip->rb, true); return 0; } @@ -1143,15 +1079,7 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg, static void azx_init_pci(struct azx *chip) { - /* force to non-snoop mode for a new VIA controller when BIOS is set */ - if (chip->snoop && chip->driver_type == AZX_DRIVER_VIA) { - u8 snoop; - pci_read_config_byte(chip->pci, 0x42, &snoop); - if (!(snoop & 0x80) && chip->pci->revision == 0x30) { - chip->snoop = 0; - snd_printdd(SFX "Force to non-snoop mode\n"); - } - } + unsigned short snoop; /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) * TCSEL == Traffic Class Select Register, which sets PCI express QOS @@ -1168,15 +1096,15 @@ static void azx_init_pci(struct azx *chip) * we need to enable snoop. */ if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) { - snd_printdd(SFX "Setting ATI snoop: %d\n", azx_snoop(chip)); + snd_printdd(SFX "Enabling ATI snoop\n"); update_pci_byte(chip->pci, - ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07, - azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0); + ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, + 0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP); } /* For NVIDIA HDA, enable snoop */ if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) { - snd_printdd(SFX "Setting Nvidia snoop: %d\n", azx_snoop(chip)); + snd_printdd(SFX "Enabling Nvidia snoop\n"); update_pci_byte(chip->pci, NVIDIA_HDA_TRANSREG_ADDR, 0x0f, NVIDIA_HDA_ENABLE_COHBITS); @@ -1190,20 +1118,16 @@ static void azx_init_pci(struct azx *chip) /* Enable SCH/PCH snoop if needed */ if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) { - unsigned short snoop; pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); - if ((!azx_snoop(chip) && !(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)) || - (azx_snoop(chip) && (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP))) { - snoop &= ~INTEL_SCH_HDA_DEVC_NOSNOOP; - if (!azx_snoop(chip)) - snoop |= INTEL_SCH_HDA_DEVC_NOSNOOP; - pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, snoop); + if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { + pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, + snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP)); pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); - } - snd_printdd(SFX "SCH snoop: %s\n", + snd_printdd(SFX "HDA snoop disabled, enabling ... %s\n", (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) - ? "Disabled" : "Enabled"); + ? "Failed" : "OK"); + } } } @@ -1410,16 +1334,12 @@ static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev) */ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) { - unsigned int val; /* make sure the run bit is zero for SD */ azx_stream_clear(chip, azx_dev); /* program the stream_tag */ - val = azx_sd_readl(azx_dev, SD_CTL); - val = (val & ~SD_CTL_STREAM_TAG_MASK) | - (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT); - if (!azx_snoop(chip)) - val |= SD_CTL_TRAFFIC_PRIO; - azx_sd_writel(azx_dev, SD_CTL, val); + azx_sd_writel(azx_dev, SD_CTL, + (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)| + (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT)); /* program the length of samples in cyclic buffer */ azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize); @@ -1613,9 +1533,6 @@ azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream) { int dev, i, nums; struct azx_dev *res = NULL; - /* make a non-zero unique key for the substream */ - int key = (substream->pcm->device << 16) | (substream->number << 2) | - (substream->stream + 1); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dev = chip->playback_index_offset; @@ -1627,12 +1544,12 @@ azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream) for (i = 0; i < nums; i++, dev++) if (!chip->azx_dev[dev].opened) { res = &chip->azx_dev[dev]; - if (res->assigned_key == key) + if (res->device == substream->pcm->device) break; } if (res) { res->opened = 1; - res->assigned_key = key; + res->device = substream->pcm->device; } return res; } @@ -1682,7 +1599,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; unsigned long flags; int err; - int buff_step; mutex_lock(&chip->open_mutex); azx_dev = azx_assign_device(chip, substream); @@ -1697,25 +1613,10 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) runtime->hw.rates = hinfo->rates; snd_pcm_limit_hw_rates(runtime); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (align_buffer_size) - /* constrain buffer sizes to be multiple of 128 - bytes. This is more efficient in terms of memory - access but isn't required by the HDA spec and - prevents users from specifying exact period/buffer - sizes. For example for 44.1kHz, a period size set - to 20ms will be rounded to 19.59ms. */ - buff_step = 128; - else - /* Don't enforce steps on buffer sizes, still need to - be multiple of 4 bytes (HDA spec). Tested on Intel - HDA controllers, may not work on all devices where - option needs to be disabled */ - buff_step = 4; - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - buff_step); + 128); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - buff_step); + 128); snd_hda_power_up(apcm->codec); err = hinfo->ops.open(hinfo, apcm->codec, substream); if (err < 0) { @@ -1770,30 +1671,19 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) static int azx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - struct snd_pcm_runtime *runtime = substream->runtime; struct azx_dev *azx_dev = get_azx_dev(substream); - int ret; - mark_runtime_wc(chip, azx_dev, runtime, false); azx_dev->bufsize = 0; azx_dev->period_bytes = 0; azx_dev->format_val = 0; - ret = snd_pcm_lib_malloc_pages(substream, + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - if (ret < 0) - return ret; - mark_runtime_wc(chip, azx_dev, runtime, true); - return ret; } static int azx_pcm_hw_free(struct snd_pcm_substream *substream) { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx_dev *azx_dev = get_azx_dev(substream); - struct azx *chip = apcm->chip; - struct snd_pcm_runtime *runtime = substream->runtime; struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; /* reset BDL address */ @@ -1806,7 +1696,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) snd_hda_codec_cleanup(apcm->codec, hinfo, substream); - mark_runtime_wc(chip, azx_dev, runtime, false); return snd_pcm_lib_free_pages(substream); } @@ -2035,8 +1924,7 @@ static unsigned int azx_via_get_position(struct azx *chip, } static unsigned int azx_get_position(struct azx *chip, - struct azx_dev *azx_dev, - bool with_check) + struct azx_dev *azx_dev) { unsigned int pos; int stream = azx_dev->substream->stream; @@ -2052,7 +1940,7 @@ static unsigned int azx_get_position(struct azx *chip, default: /* use the position buffer */ pos = le32_to_cpu(*azx_dev->posbuf); - if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) { + if (chip->position_fix[stream] == POS_FIX_AUTO) { if (!pos || pos == (u32)-1) { printk(KERN_WARNING "hda-intel: Invalid position buffer, " @@ -2076,7 +1964,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) struct azx *chip = apcm->chip; struct azx_dev *azx_dev = get_azx_dev(substream); return bytes_to_frames(substream->runtime, - azx_get_position(chip, azx_dev, false)); + azx_get_position(chip, azx_dev)); } /* @@ -2099,7 +1987,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) return -1; /* bogus (too early) interrupt */ stream = azx_dev->substream->stream; - pos = azx_get_position(chip, azx_dev, true); + pos = azx_get_position(chip, azx_dev); if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) @@ -2166,20 +2054,6 @@ static void azx_clear_irq_pending(struct azx *chip) spin_unlock_irq(&chip->reg_lock); } -#ifdef CONFIG_X86 -static int azx_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *area) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - if (!azx_snoop(chip)) - area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); - return snd_pcm_lib_default_mmap(substream, area); -} -#else -#define azx_pcm_mmap NULL -#endif - static struct snd_pcm_ops azx_pcm_ops = { .open = azx_pcm_open, .close = azx_pcm_close, @@ -2189,7 +2063,6 @@ static struct snd_pcm_ops azx_pcm_ops = { .prepare = azx_pcm_prepare, .trigger = azx_pcm_trigger, .pointer = azx_pcm_pointer, - .mmap = azx_pcm_mmap, .page = snd_pcm_sgbuf_ops_page, }; @@ -2470,19 +2343,13 @@ static int azx_free(struct azx *chip) if (chip->azx_dev) { for (i = 0; i < chip->num_streams; i++) - if (chip->azx_dev[i].bdl.area) { - mark_pages_wc(chip, &chip->azx_dev[i].bdl, false); + if (chip->azx_dev[i].bdl.area) snd_dma_free_pages(&chip->azx_dev[i].bdl); - } } - if (chip->rb.area) { - mark_pages_wc(chip, &chip->rb, false); + if (chip->rb.area) snd_dma_free_pages(&chip->rb); - } - if (chip->posbuf.area) { - mark_pages_wc(chip, &chip->posbuf, false); + if (chip->posbuf.area) snd_dma_free_pages(&chip->posbuf); - } pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip->azx_dev); @@ -2502,7 +2369,6 @@ static int azx_dev_free(struct snd_device *device) static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), - SND_PCI_QUIRK(0x1028, 0x02c6, "Dell Inspiron 1010", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), @@ -2678,7 +2544,6 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, check_probe_mask(chip, dev); chip->single_cmd = single_cmd; - chip->snoop = hda_snoop; if (bdl_pos_adj[dev] < 0) { switch (chip->driver_type) { @@ -2751,10 +2616,6 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, gcap &= ~ICH6_GCAP_64OK; } - /* disable buffer size rounding to 128-byte multiples if supported */ - if (chip->driver_caps & AZX_DCAPS_BUFSIZE) - align_buffer_size = 0; - /* allow 64bit DMA address if supported by H/W */ if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); @@ -2806,7 +2667,6 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); goto errout; } - mark_pages_wc(chip, &chip->azx_dev[i].bdl, true); } /* allocate memory for the position buffer */ err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, @@ -2816,7 +2676,6 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); goto errout; } - mark_pages_wc(chip, &chip->posbuf, true); /* allocate CORB/RIRB */ err = azx_alloc_cmd_io(chip); if (err < 0) @@ -2958,49 +2817,37 @@ static void __devexit azx_remove(struct pci_dev *pci) static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, /* PBG */ { PCI_DEVICE(0x8086, 0x1d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE}, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE}, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE}, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP }, { PCI_DEVICE(0x8086, 0x2668), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH6 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH6 */ { PCI_DEVICE(0x8086, 0x27d8), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH7 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH7 */ { PCI_DEVICE(0x8086, 0x269a), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ESB2 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ESB2 */ { PCI_DEVICE(0x8086, 0x284b), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH8 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH8 */ { PCI_DEVICE(0x8086, 0x293e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH9 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */ { PCI_DEVICE(0x8086, 0x293f), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH9 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */ { PCI_DEVICE(0x8086, 0x3a3e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH10 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */ { PCI_DEVICE(0x8086, 0x3a6e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH10 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */ /* Generic Intel */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_BUFSIZE }, + .driver_data = AZX_DRIVER_ICH }, /* ATI SB 450/600/700/800/900 */ { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, diff --git a/trunk/sound/pci/hda/hda_local.h b/trunk/sound/pci/hda/hda_local.h index 79f49e2e8cbc..2e7ac31afa8d 100644 --- a/trunk/sound/pci/hda/hda_local.h +++ b/trunk/sound/pci/hda/hda_local.h @@ -267,14 +267,11 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, enum { HDA_FRONT, HDA_REAR, HDA_CLFE, HDA_SIDE }; /* index for dac_nidx */ enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */ -#define HDA_MAX_OUTS 5 - struct hda_multi_out { int num_dacs; /* # of DACs, must be more than 1 */ const hda_nid_t *dac_nids; /* DAC list */ hda_nid_t hp_nid; /* optional DAC for HP, 0 when not exists */ - hda_nid_t hp_out_nid[HDA_MAX_OUTS]; /* DACs for multiple HPs */ - hda_nid_t extra_out_nid[HDA_MAX_OUTS]; /* other (e.g. speaker) DACs */ + hda_nid_t extra_out_nid[3]; /* optional DACs, 0 when not exists */ hda_nid_t dig_out_nid; /* digital out audio widget */ const hda_nid_t *slave_dig_outs; int max_channels; /* currently supported analog channels */ @@ -336,6 +333,9 @@ int snd_hda_codec_proc_new(struct hda_codec *codec); static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } #endif +#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 +void snd_print_pcm_rates(int pcm, char *buf, int buflen); + #define SND_PRINT_BITS_ADVISED_BUFSIZE 16 void snd_print_pcm_bits(int pcm, char *buf, int buflen); @@ -385,7 +385,7 @@ enum { AUTO_PIN_HP_OUT }; -#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS +#define AUTO_CFG_MAX_OUTS 5 #define AUTO_CFG_MAX_INS 8 struct auto_pin_cfg_item { @@ -442,21 +442,10 @@ struct auto_pin_cfg { (cfg & AC_DEFCFG_SEQUENCE) #define get_defcfg_device(cfg) \ ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) -#define get_defcfg_misc(cfg) \ - ((cfg & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) - -/* bit-flags for snd_hda_parse_pin_def_config() behavior */ -#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */ -#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */ -int snd_hda_parse_pin_defcfg(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - const hda_nid_t *ignore_nids, - unsigned int cond_flags); - -/* older function */ -#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \ - snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0) +int snd_hda_parse_pin_def_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg, + const hda_nid_t *ignore_nids); /* amp values */ #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) @@ -503,16 +492,12 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); -int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, - unsigned int caps); u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) { return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) && - !(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid) & - AC_DEFCFG_MISC_NO_PRESENCE)) && (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP); } @@ -604,8 +589,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, #define get_amp_nid_(pv) ((pv) & 0xffff) #define get_amp_nid(kc) get_amp_nid_((kc)->private_value) #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) -#define get_amp_direction_(pv) (((pv) >> 18) & 0x1) -#define get_amp_direction(kc) get_amp_direction_((kc)->private_value) +#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) #define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) #define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1) @@ -623,7 +607,6 @@ struct cea_sad { }; #define ELD_FIXED_BYTES 20 -#define ELD_MAX_SIZE 256 #define ELD_MAX_MNL 16 #define ELD_MAX_SAD 16 @@ -648,7 +631,6 @@ struct hdmi_eld { int spk_alloc; int sad_count; struct cea_sad sad[ELD_MAX_SAD]; - char eld_buffer[ELD_MAX_SIZE]; #ifdef CONFIG_PROC_FS struct snd_info_entry *proc_entry; #endif diff --git a/trunk/sound/pci/hda/hda_proc.c b/trunk/sound/pci/hda/hda_proc.c index 2c981b55940b..2be57b051aa2 100644 --- a/trunk/sound/pci/hda/hda_proc.c +++ b/trunk/sound/pci/hda/hda_proc.c @@ -152,18 +152,12 @@ static void print_amp_vals(struct snd_info_buffer *buffer, static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) { - static unsigned int rates[] = { - 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, - 96000, 176400, 192000, 384000 - }; - int i; + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; pcm &= AC_SUPPCM_RATES; snd_iprintf(buffer, " rates [0x%x]:", pcm); - for (i = 0; i < ARRAY_SIZE(rates); i++) - if (pcm & (1 << i)) - snd_iprintf(buffer, " %d", rates[i]); - snd_iprintf(buffer, "\n"); + snd_print_pcm_rates(pcm, buf, sizeof(buf)); + snd_iprintf(buffer, "%s\n", buf); } static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) diff --git a/trunk/sound/pci/hda/hda_trace.h b/trunk/sound/pci/hda/hda_trace.h deleted file mode 100644 index 9884871ddb00..000000000000 --- a/trunk/sound/pci/hda/hda_trace.h +++ /dev/null @@ -1,117 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM hda -#define TRACE_INCLUDE_FILE hda_trace - -#if !defined(_TRACE_HDA_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_HDA_H - -#include - -struct hda_bus; -struct hda_codec; - -DECLARE_EVENT_CLASS(hda_cmd, - - TP_PROTO(struct hda_codec *codec, unsigned int val), - - TP_ARGS(codec, val), - - TP_STRUCT__entry( - __field( unsigned int, card ) - __field( unsigned int, addr ) - __field( unsigned int, val ) - ), - - TP_fast_assign( - __entry->card = (codec)->bus->card->number; - __entry->addr = (codec)->addr; - __entry->val = (val); - ), - - TP_printk("[%d:%d] val=%x", __entry->card, __entry->addr, __entry->val) -); - -DEFINE_EVENT(hda_cmd, hda_send_cmd, - TP_PROTO(struct hda_codec *codec, unsigned int val), - TP_ARGS(codec, val) -); - -DEFINE_EVENT(hda_cmd, hda_get_response, - TP_PROTO(struct hda_codec *codec, unsigned int val), - TP_ARGS(codec, val) -); - -TRACE_EVENT(hda_bus_reset, - - TP_PROTO(struct hda_bus *bus), - - TP_ARGS(bus), - - TP_STRUCT__entry( - __field( unsigned int, card ) - ), - - TP_fast_assign( - __entry->card = (bus)->card->number; - ), - - TP_printk("[%d]", __entry->card) -); - -DECLARE_EVENT_CLASS(hda_power, - - TP_PROTO(struct hda_codec *codec), - - TP_ARGS(codec), - - TP_STRUCT__entry( - __field( unsigned int, card ) - __field( unsigned int, addr ) - ), - - TP_fast_assign( - __entry->card = (codec)->bus->card->number; - __entry->addr = (codec)->addr; - ), - - TP_printk("[%d:%d]", __entry->card, __entry->addr) -); - -DEFINE_EVENT(hda_power, hda_power_down, - TP_PROTO(struct hda_codec *codec), - TP_ARGS(codec) -); - -DEFINE_EVENT(hda_power, hda_power_up, - TP_PROTO(struct hda_codec *codec), - TP_ARGS(codec) -); - -TRACE_EVENT(hda_unsol_event, - - TP_PROTO(struct hda_bus *bus, u32 res, u32 res_ex), - - TP_ARGS(bus, res, res_ex), - - TP_STRUCT__entry( - __field( unsigned int, card ) - __field( u32, res ) - __field( u32, res_ex ) - ), - - TP_fast_assign( - __entry->card = (bus)->card->number; - __entry->res = res; - __entry->res_ex = res_ex; - ), - - TP_printk("[%d] res=%x, res_ex=%x", __entry->card, - __entry->res, __entry->res_ex) -); - -#endif /* _TRACE_HDA_H */ - -/* This part must be outside protection */ -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . -#include diff --git a/trunk/sound/pci/hda/patch_analog.c b/trunk/sound/pci/hda/patch_analog.c index d8aac588f23b..8648917acffb 100644 --- a/trunk/sound/pci/hda/patch_analog.c +++ b/trunk/sound/pci/hda/patch_analog.c @@ -48,8 +48,6 @@ struct ad198x_spec { const hda_nid_t *alt_dac_nid; const struct hda_pcm_stream *stream_analog_alt_playback; - int independent_hp; - int num_active_streams; /* capture */ unsigned int num_adc_nids; @@ -304,72 +302,6 @@ static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) } #endif -static void activate_ctl(struct hda_codec *codec, const char *name, int active) -{ - struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name); - if (ctl) { - ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - ctl->vd[0].access |= active ? 0 : - SNDRV_CTL_ELEM_ACCESS_INACTIVE; - ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE; - ctl->vd[0].access |= active ? - SNDRV_CTL_ELEM_ACCESS_WRITE : 0; - snd_ctl_notify(codec->bus->card, - SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); - } -} - -static void set_stream_active(struct hda_codec *codec, bool active) -{ - struct ad198x_spec *spec = codec->spec; - if (active) - spec->num_active_streams++; - else - spec->num_active_streams--; - activate_ctl(codec, "Independent HP", spec->num_active_streams == 0); -} - -static int ad1988_independent_hp_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { "OFF", "ON", NULL}; - int index; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - index = uinfo->value.enumerated.item; - if (index >= 2) - index = 1; - strcpy(uinfo->value.enumerated.name, texts[index]); - return 0; -} - -static int ad1988_independent_hp_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->independent_hp; - return 0; -} - -static int ad1988_independent_hp_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - unsigned int select = ucontrol->value.enumerated.item[0]; - if (spec->independent_hp != select) { - spec->independent_hp = select; - if (spec->independent_hp) - spec->multiout.hp_nid = 0; - else - spec->multiout.hp_nid = spec->alt_dac_nid[0]; - return 1; - } - return 0; -} - /* * Analog playback callbacks */ @@ -378,15 +310,8 @@ static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct ad198x_spec *spec = codec->spec; - int err; - set_stream_active(codec, true); - err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, hinfo); - if (err < 0) { - set_stream_active(codec, false); - return err; - } - return 0; } static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -408,41 +333,11 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); } -static int ad198x_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_active(codec, false); - return 0; -} - -static int ad1988_alt_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - if (!spec->independent_hp) - return -EBUSY; - set_stream_active(codec, true); - return 0; -} - -static int ad1988_alt_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_active(codec, false); - return 0; -} - static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, - .ops = { - .open = ad1988_alt_playback_pcm_open, - .close = ad1988_alt_playback_pcm_close - }, + /* NID is set in ad198x_build_pcms */ }; /* @@ -507,6 +402,7 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } + /* */ static const struct hda_pcm_stream ad198x_pcm_analog_playback = { @@ -517,8 +413,7 @@ static const struct hda_pcm_stream ad198x_pcm_analog_playback = { .ops = { .open = ad198x_playback_pcm_open, .prepare = ad198x_playback_pcm_prepare, - .cleanup = ad198x_playback_pcm_cleanup, - .close = ad198x_playback_pcm_close + .cleanup = ad198x_playback_pcm_cleanup }, }; @@ -2163,6 +2058,7 @@ static int patch_ad1981(struct hda_codec *codec) enum { AD1988_6STACK, AD1988_6STACK_DIG, + AD1988_6STACK_DIG_FP, AD1988_3STACK, AD1988_3STACK_DIG, AD1988_LAPTOP, @@ -2272,17 +2168,6 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, return err; } -static const struct snd_kcontrol_new ad1988_hp_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Independent HP", - .info = ad1988_independent_hp_info, - .get = ad1988_independent_hp_get, - .put = ad1988_independent_hp_put, - }, - { } /* end */ -}; - /* 6-stack mode */ static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), @@ -2303,7 +2188,6 @@ static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { }; static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), @@ -2326,6 +2210,13 @@ static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = { HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), + + { } /* end */ +}; + +static const struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + { } /* end */ }; @@ -2347,7 +2238,6 @@ static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { }; static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT), HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT), @@ -2382,7 +2272,6 @@ static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = { /* laptop mode */ static const struct snd_kcontrol_new ad1988_laptop_mixers[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT), HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), @@ -2557,7 +2446,7 @@ static const struct hda_verb ad1988_6stack_init_verbs[] = { {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ + {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -2705,7 +2594,7 @@ static const struct hda_verb ad1988_3stack_init_verbs[] = { {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ + {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -2780,7 +2669,7 @@ static const struct hda_verb ad1988_laptop_init_verbs[] = { {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ + {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -2893,11 +2782,11 @@ static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx) { static const hda_nid_t idx_to_dac[8] = { /* A B C D E F G H */ - 0x03, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a + 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a }; static const hda_nid_t idx_to_dac_rev2[8] = { /* A B C D E F G H */ - 0x03, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06 + 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06 }; if (is_rev2(codec)) return idx_to_dac_rev2[idx]; @@ -3134,8 +3023,8 @@ static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); switch (nid) { - case 0x11: /* port-A - DAC 03 */ - snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x00); + case 0x11: /* port-A - DAC 04 */ + snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01); break; case 0x14: /* port-B - DAC 06 */ snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02); @@ -3261,6 +3150,7 @@ static int ad1988_auto_init(struct hda_codec *codec) static const char * const ad1988_models[AD1988_MODEL_LAST] = { [AD1988_6STACK] = "6stack", [AD1988_6STACK_DIG] = "6stack-dig", + [AD1988_6STACK_DIG_FP] = "6stack-dig-fp", [AD1988_3STACK] = "3stack", [AD1988_3STACK_DIG] = "3stack-dig", [AD1988_LAPTOP] = "laptop", @@ -3318,11 +3208,10 @@ static int patch_ad1988(struct hda_codec *codec) } set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = ad1988_alt_dac_nid[0]; switch (board_config) { case AD1988_6STACK: case AD1988_6STACK_DIG: + case AD1988_6STACK_DIG_FP: spec->multiout.max_channels = 8; spec->multiout.num_dacs = 4; if (is_rev2(codec)) @@ -3338,7 +3227,19 @@ static int patch_ad1988(struct hda_codec *codec) spec->mixers[1] = ad1988_6stack_mixers2; spec->num_init_verbs = 1; spec->init_verbs[0] = ad1988_6stack_init_verbs; - if (board_config == AD1988_6STACK_DIG) { + if (board_config == AD1988_6STACK_DIG_FP) { + spec->num_mixers++; + spec->mixers[2] = ad1988_6stack_fp_mixers; + spec->num_init_verbs++; + spec->init_verbs[1] = ad1988_6stack_fp_init_verbs; + spec->slave_vols = ad1988_6stack_fp_slave_vols; + spec->slave_sws = ad1988_6stack_fp_slave_sws; + spec->alt_dac_nid = ad1988_alt_dac_nid; + spec->stream_analog_alt_playback = + &ad198x_pcm_analog_alt_playback; + } + if ((board_config == AD1988_6STACK_DIG) || + (board_config == AD1988_6STACK_DIG_FP)) { spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; spec->dig_in_nid = AD1988_SPDIF_IN; } @@ -3381,15 +3282,6 @@ static int patch_ad1988(struct hda_codec *codec) break; } - if (spec->autocfg.hp_pins[0]) { - spec->mixers[spec->num_mixers++] = ad1988_hp_mixers; - spec->slave_vols = ad1988_6stack_fp_slave_vols; - spec->slave_sws = ad1988_6stack_fp_slave_sws; - spec->alt_dac_nid = ad1988_alt_dac_nid; - spec->stream_analog_alt_playback = - &ad198x_pcm_analog_alt_playback; - } - spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); spec->adc_nids = ad1988_adc_nids; spec->capsrc_nids = ad1988_capsrc_nids; diff --git a/trunk/sound/pci/hda/patch_cirrus.c b/trunk/sound/pci/hda/patch_cirrus.c index c45f3e69bcf0..47d6ffc9b5b5 100644 --- a/trunk/sound/pci/hda/patch_cirrus.c +++ b/trunk/sound/pci/hda/patch_cirrus.c @@ -375,7 +375,7 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx) static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, unsigned int *idxp) { - int i, idx; + int i; hda_nid_t nid; nid = codec->start_nid; @@ -384,11 +384,9 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, type = get_wcaps_type(get_wcaps(codec, nid)); if (type != AC_WID_AUD_IN) continue; - idx = snd_hda_get_conn_index(codec, nid, pin, false); - if (idx >= 0) { - *idxp = idx; + *idxp = snd_hda_get_conn_index(codec, nid, pin, false); + if (*idxp >= 0) return nid; - } } return 0; } @@ -535,7 +533,7 @@ static int add_volume(struct hda_codec *codec, const char *name, int index, unsigned int pval, int dir, struct snd_kcontrol **kctlp) { - char tmp[44]; + char tmp[32]; struct snd_kcontrol_new knew = HDA_CODEC_VOLUME_IDX(tmp, index, 0, 0, HDA_OUTPUT); knew.private_value = pval; diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index 0c8b5a1993ed..502fc9499453 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -136,8 +136,6 @@ struct conexant_spec { unsigned int thinkpad:1; unsigned int hp_laptop:1; unsigned int asus:1; - unsigned int pin_eapd_ctrls:1; - unsigned int single_adc_amp:1; unsigned int adc_switching:1; @@ -1869,6 +1867,39 @@ static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { { } /* end */ }; +static const struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { + /* Line in, Mic */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, + /* SPK */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP, Amp */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Docking HP */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* DAC1 */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Record selector: Internal mic */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, + /* SPDIF route: PCM */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* needed for W500 Advanced Mini Dock 250410 */ + {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* EAPD */ + {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, + { } /* end */ +}; + static const struct hda_verb cxt5051_f700_init_verbs[] = { /* Line in, Mic */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, @@ -1937,6 +1968,7 @@ enum { CXT5051_LAPTOP, /* Laptops w/ EAPD support */ CXT5051_HP, /* no docking */ CXT5051_HP_DV6736, /* HP without mic switch */ + CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */ CXT5051_F700, /* HP Compaq Presario F700 */ CXT5051_TOSHIBA, /* Toshiba M300 & co */ CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ @@ -1948,6 +1980,7 @@ static const char *const cxt5051_models[CXT5051_MODELS] = { [CXT5051_LAPTOP] = "laptop", [CXT5051_HP] = "hp", [CXT5051_HP_DV6736] = "hp-dv6736", + [CXT5051_LENOVO_X200] = "lenovo-x200", [CXT5051_F700] = "hp-700", [CXT5051_TOSHIBA] = "toshiba", [CXT5051_IDEAPAD] = "ideapad", @@ -1962,6 +1995,7 @@ static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", CXT5051_LAPTOP), SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), + SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD), {} }; @@ -2019,6 +2053,13 @@ static int patch_cxt5051(struct hda_codec *codec) spec->mixers[0] = cxt5051_hp_dv6736_mixers; spec->auto_mic = 0; break; + case CXT5051_LENOVO_X200: + spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; + /* Thinkpad X301 does not have S/PDIF wired and no ability + to use a docking station. */ + if (codec->subsystem_id == 0x17aa211f) + spec->multiout.dig_out_nid = 0; + break; case CXT5051_F700: spec->init_verbs[0] = cxt5051_f700_init_verbs; spec->mixers[0] = cxt5051_f700_mixers; @@ -3069,7 +3110,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO), SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), @@ -3308,8 +3348,6 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin, #define MAX_AUTO_DACS 5 -#define DAC_SLAVE_FLAG 0x8000 /* filled dac is a slave */ - /* fill analog DAC list from the widget tree */ static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs) { @@ -3332,26 +3370,16 @@ static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs) /* fill pin_dac_pair list from the pin and dac list */ static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins, int num_pins, hda_nid_t *dacs, int *rest, - struct pin_dac_pair *filled, int nums, - int type) + struct pin_dac_pair *filled, int type) { - int i, start = nums; + int i, nums; - for (i = 0; i < num_pins; i++, nums++) { + nums = 0; + for (i = 0; i < num_pins; i++) { filled[nums].pin = pins[i]; filled[nums].type = type; filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest); - if (filled[nums].dac) - continue; - if (filled[start].dac && get_connection_index(codec, pins[i], filled[start].dac) >= 0) { - filled[nums].dac = filled[start].dac | DAC_SLAVE_FLAG; - continue; - } - if (filled[0].dac && get_connection_index(codec, pins[i], filled[0].dac) >= 0) { - filled[nums].dac = filled[0].dac | DAC_SLAVE_FLAG; - continue; - } - snd_printdd("Failed to find a DAC for pin 0x%x", pins[i]); + nums++; } return nums; } @@ -3367,19 +3395,19 @@ static void cx_auto_parse_output(struct hda_codec *codec) rest = fill_cx_auto_dacs(codec, dacs); /* parse all analog output pins */ nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs, - dacs, &rest, spec->dac_info, 0, - AUTO_PIN_LINE_OUT); - nums = fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs, - dacs, &rest, spec->dac_info, nums, - AUTO_PIN_HP_OUT); - nums = fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs, - dacs, &rest, spec->dac_info, nums, - AUTO_PIN_SPEAKER_OUT); + dacs, &rest, spec->dac_info, + AUTO_PIN_LINE_OUT); + nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs, + dacs, &rest, spec->dac_info + nums, + AUTO_PIN_HP_OUT); + nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs, + dacs, &rest, spec->dac_info + nums, + AUTO_PIN_SPEAKER_OUT); spec->dac_info_filled = nums; /* fill multiout struct */ for (i = 0; i < nums; i++) { hda_nid_t dac = spec->dac_info[i].dac; - if (!dac || (dac & DAC_SLAVE_FLAG)) + if (!dac) continue; switch (spec->dac_info[i].type) { case AUTO_PIN_LINE_OUT: @@ -3432,14 +3460,12 @@ static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, bool on) { - struct conexant_spec *spec = codec->spec; int i; for (i = 0; i < num_pins; i++) snd_hda_codec_write(codec, pins[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, on ? PIN_OUT : 0); - if (spec->pin_eapd_ctrls) - cx_auto_turn_eapd(codec, num_pins, pins, on); + cx_auto_turn_eapd(codec, num_pins, pins, on); } static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) @@ -3464,12 +3490,9 @@ static void cx_auto_update_speakers(struct hda_codec *codec) int on = 1; /* turn on HP EAPD when HP jacks are present */ - if (spec->pin_eapd_ctrls) { - if (spec->auto_mute) - on = spec->hp_present; - cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); - } - + if (spec->auto_mute) + on = spec->hp_present; + cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); /* mute speakers in auto-mode if HP or LO jacks are plugged */ if (spec->auto_mute) on = !(spec->hp_present || @@ -3839,7 +3862,7 @@ static void cx_auto_parse_input(struct hda_codec *codec) } if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items) cx_auto_check_auto_mic(codec); - if (imux->num_items > 1) { + if (imux->num_items > 1 && !spec->auto_mic) { for (i = 1; i < imux->num_items; i++) { if (spec->imux_info[i].adc != spec->imux_info[0].adc) { spec->adc_switching = 1; @@ -3896,10 +3919,20 @@ static void cx_auto_parse_beep(struct hda_codec *codec) #define cx_auto_parse_beep(codec) #endif -/* parse EAPDs */ +static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) +{ + int i; + for (i = 0; i < nums; i++) + if (list[i] == nid) + return true; + return false; +} + +/* parse extra-EAPD that aren't assigned to any pins */ static void cx_auto_parse_eapd(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid, end_nid; end_nid = codec->start_nid + codec->num_nodes; @@ -3908,18 +3941,14 @@ static void cx_auto_parse_eapd(struct hda_codec *codec) continue; if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) continue; + if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) || + found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) || + found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs)) + continue; spec->eapds[spec->num_eapds++] = nid; if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) break; } - - /* NOTE: below is a wild guess; if we have more than two EAPDs, - * it's a new chip, where EAPDs are supposed to be associated to - * pins, and we can control EAPD per pin. - * OTOH, if only one or two EAPDs are found, it's an old chip, - * thus it might control over all pins. - */ - spec->pin_eapd_ctrls = spec->num_eapds > 2; } static int cx_auto_parse_auto_config(struct hda_codec *codec) @@ -4006,8 +4035,6 @@ static void cx_auto_init_output(struct hda_codec *codec) nid = spec->dac_info[i].dac; if (!nid) nid = spec->multiout.dac_nids[0]; - else if (nid & DAC_SLAVE_FLAG) - nid &= ~DAC_SLAVE_FLAG; select_connection(codec, spec->dac_info[i].pin, nid); } if (spec->auto_mute) { @@ -4025,9 +4052,8 @@ static void cx_auto_init_output(struct hda_codec *codec) } } cx_auto_update_speakers(codec); - /* turn on all EAPDs if no individual EAPD control is available */ - if (!spec->pin_eapd_ctrls) - cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); + /* turn on/off extra EAPDs, too */ + cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); } static void cx_auto_init_input(struct hda_codec *codec) @@ -4141,11 +4167,9 @@ static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac, hda_nid_t pin, const char *name, int idx) { unsigned int caps; - if (dac && !(dac & DAC_SLAVE_FLAG)) { - caps = query_amp_caps(codec, dac, HDA_OUTPUT); - if (caps & AC_AMPCAP_NUM_STEPS) - return cx_auto_add_pb_volume(codec, dac, name, idx); - } + caps = query_amp_caps(codec, dac, HDA_OUTPUT); + if (caps & AC_AMPCAP_NUM_STEPS) + return cx_auto_add_pb_volume(codec, dac, name, idx); caps = query_amp_caps(codec, pin, HDA_OUTPUT); if (caps & AC_AMPCAP_NUM_STEPS) return cx_auto_add_pb_volume(codec, pin, name, idx); @@ -4167,7 +4191,8 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) for (i = 0; i < spec->dac_info_filled; i++) { const char *label; int idx, type; - hda_nid_t dac = spec->dac_info[i].dac; + if (!spec->dac_info[i].dac) + continue; type = spec->dac_info[i].type; if (type == AUTO_PIN_LINE_OUT) type = spec->autocfg.line_out_type; @@ -4186,7 +4211,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) idx = num_spk++; break; } - err = try_add_pb_volume(codec, dac, + err = try_add_pb_volume(codec, spec->dac_info[i].dac, spec->dac_info[i].pin, label, idx); if (err < 0) @@ -4214,8 +4239,6 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, int idx = get_input_connection(codec, adc_nid, nid); if (idx < 0) continue; - if (spec->single_adc_amp) - idx = 0; return cx_auto_add_volume_idx(codec, label, pfx, cidx, adc_nid, HDA_INPUT, idx); } @@ -4256,21 +4279,14 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) struct hda_input_mux *imux = &spec->private_imux; const char *prev_label; int input_conn[HDA_MAX_NUM_INPUTS]; - int i, j, err, cidx; + int i, err, cidx; int multi_connection; - if (!imux->num_items) - return 0; - multi_connection = 0; for (i = 0; i < imux->num_items; i++) { cidx = get_input_connection(codec, spec->imux_info[i].adc, spec->imux_info[i].pin); - if (cidx < 0) - continue; - input_conn[i] = spec->imux_info[i].adc; - if (!spec->single_adc_amp) - input_conn[i] |= cidx << 8; + input_conn[i] = (spec->imux_info[i].adc << 8) | cidx; if (i > 0 && input_conn[i] != input_conn[0]) multi_connection = 1; } @@ -4299,15 +4315,6 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) err = cx_auto_add_capture_volume(codec, nid, "Capture", "", cidx); } else { - bool dup_found = false; - for (j = 0; j < i; j++) { - if (input_conn[j] == input_conn[i]) { - dup_found = true; - break; - } - } - if (dup_found) - continue; err = cx_auto_add_capture_volume(codec, nid, label, " Capture", cidx); } @@ -4371,53 +4378,6 @@ static const struct hda_codec_ops cx_auto_patch_ops = { .reboot_notify = snd_hda_shutup_pins, }; -/* - * pin fix-up - */ -struct cxt_pincfg { - hda_nid_t nid; - u32 val; -}; - -static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg) -{ - for (; cfg->nid; cfg++) - snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); - -} - -static void apply_pin_fixup(struct hda_codec *codec, - const struct snd_pci_quirk *quirk, - const struct cxt_pincfg **table) -{ - quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk); - if (quirk) { - snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n", - quirk->name); - apply_pincfg(codec, table[quirk->value]); - } -} - -enum { - CXT_PINCFG_LENOVO_X200, -}; - -static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = { - { 0x16, 0x042140ff }, /* HP (seq# overridden) */ - { 0x17, 0x21a11000 }, /* dock-mic */ - { 0x19, 0x2121103f }, /* dock-HP */ - {} -}; - -static const struct cxt_pincfg *cxt_pincfg_tbl[] = { - [CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200, -}; - -static const struct snd_pci_quirk cxt_fixups[] = { - SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200), - {} -}; - static int patch_conexant_auto(struct hda_codec *codec) { struct conexant_spec *spec; @@ -4431,15 +4391,6 @@ static int patch_conexant_auto(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; codec->pin_amp_workaround = 1; - - switch (codec->vendor_id) { - case 0x14f15045: - spec->single_adc_amp = 1; - break; - } - - apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl); - err = cx_auto_search_adcs(codec); if (err < 0) return err; diff --git a/trunk/sound/pci/hda/patch_hdmi.c b/trunk/sound/pci/hda/patch_hdmi.c index aac3bfacda3f..19cb72db9c38 100644 --- a/trunk/sound/pci/hda/patch_hdmi.c +++ b/trunk/sound/pci/hda/patch_hdmi.c @@ -324,66 +324,6 @@ static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid) return -EINVAL; } -static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hdmi_spec *spec; - int pin_idx; - - spec = codec->spec; - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - - pin_idx = kcontrol->private_value; - uinfo->count = spec->pins[pin_idx].sink_eld.eld_size; - - return 0; -} - -static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hdmi_spec *spec; - int pin_idx; - - spec = codec->spec; - pin_idx = kcontrol->private_value; - - memcpy(ucontrol->value.bytes.data, - spec->pins[pin_idx].sink_eld.eld_buffer, ELD_MAX_SIZE); - - return 0; -} - -static struct snd_kcontrol_new eld_bytes_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "ELD", - .info = hdmi_eld_ctl_info, - .get = hdmi_eld_ctl_get, -}; - -static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx, - int device) -{ - struct snd_kcontrol *kctl; - struct hdmi_spec *spec = codec->spec; - int err; - - kctl = snd_ctl_new1(&eld_bytes_ctl, codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = pin_idx; - kctl->id.device = device; - - err = snd_hda_ctl_add(codec, spec->pins[pin_idx].pin_nid, kctl); - if (err < 0) - return err; - - return 0; -} - #ifdef BE_PARANOID static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, int *packet_index, int *byte_index) @@ -1006,6 +946,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) unsigned int caps, config; int pin_idx; struct hdmi_spec_per_pin *per_pin; + struct hdmi_eld *eld; int err; caps = snd_hda_param_read(codec, pin_nid, AC_PAR_PIN_CAP); @@ -1022,15 +963,23 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) pin_idx = spec->num_pins; per_pin = &spec->pins[pin_idx]; + eld = &per_pin->sink_eld; per_pin->pin_nid = pin_nid; + err = snd_hda_input_jack_add(codec, pin_nid, + SND_JACK_VIDEOOUT, NULL); + if (err < 0) + return err; + err = hdmi_read_pin_conn(codec, pin_idx); if (err < 0) return err; spec->num_pins++; + hdmi_present_sense(codec, pin_nid, eld); + return 0; } @@ -1213,25 +1162,6 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) return 0; } -static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) -{ - int err; - char hdmi_str[32]; - struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - int pcmdev = spec->pcm_rec[pin_idx].device; - - snprintf(hdmi_str, sizeof(hdmi_str), "HDMI/DP,pcm=%d", pcmdev); - - err = snd_hda_input_jack_add(codec, per_pin->pin_nid, - SND_JACK_VIDEOOUT, pcmdev > 0 ? hdmi_str : NULL); - if (err < 0) - return err; - - hdmi_present_sense(codec, per_pin->pin_nid, &per_pin->sink_eld); - return 0; -} - static int generic_hdmi_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; @@ -1240,25 +1170,12 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - - err = generic_hdmi_build_jack(codec, pin_idx); - if (err < 0) - return err; - err = snd_hda_create_spdif_out_ctls(codec, per_pin->pin_nid, per_pin->mux_nids[0]); if (err < 0) return err; snd_hda_spdif_ctls_unassign(codec, pin_idx); - - /* add control for ELD Bytes */ - err = hdmi_create_eld_ctl(codec, - pin_idx, - spec->pcm_rec[pin_idx].device); - - if (err < 0) - return err; } return 0; @@ -1574,7 +1491,7 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { int chs; - unsigned int dataDCC2, channel_id; + unsigned int dataDCC1, dataDCC2, channel_id; int i; struct hdmi_spec *spec = codec->spec; struct hda_spdif_out *spdif = @@ -1584,6 +1501,7 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, chs = substream->runtime->channels; + dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT; dataDCC2 = 0x2; /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 80d6add8a620..e125c60fe352 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -116,8 +116,6 @@ struct alc_spec { const hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ hda_nid_t mixer_nid; /* analog-mixer NID */ - DECLARE_BITMAP(vol_ctls, 0x20 << 1); - DECLARE_BITMAP(sw_ctls, 0x20 << 1); /* capture setup for dynamic dual-adc switch */ hda_nid_t cur_adc; @@ -161,27 +159,23 @@ struct alc_spec { void (*power_hook)(struct hda_codec *codec); #endif void (*shutup)(struct hda_codec *codec); - void (*automute_hook)(struct hda_codec *codec); /* for pin sensing */ - unsigned int hp_jack_present:1; + unsigned int jack_present: 1; unsigned int line_jack_present:1; unsigned int master_mute:1; unsigned int auto_mic:1; unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */ - unsigned int automute_speaker:1; /* automute speaker outputs */ - unsigned int automute_lo:1; /* automute LO outputs */ - unsigned int detect_hp:1; /* Headphone detection enabled */ - unsigned int detect_lo:1; /* Line-out detection enabled */ - unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */ - unsigned int automute_lo_possible:1; /* there are line outs and HP */ + unsigned int automute:1; /* HP automute enabled */ + unsigned int detect_line:1; /* Line-out detection enabled */ + unsigned int automute_lines:1; /* automute line-out as well */ + unsigned int automute_hp_lo:1; /* both HP and LO available */ /* other flags */ unsigned int no_analog :1; /* digital I/O only */ unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */ unsigned int single_input_src:1; unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ - unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ /* auto-mute control */ int automute_mode; @@ -199,7 +193,6 @@ struct alc_spec { /* for PLL fix */ hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; - unsigned int coef0; /* fix-up list */ int fixup_id; @@ -209,9 +202,6 @@ struct alc_spec { /* multi-io */ int multi_ios; struct alc_multi_io multi_io[4]; - - /* bind volumes */ - struct snd_array bind_ctls; }; #define ALC_MODEL_AUTO 0 /* common for all chips */ @@ -535,8 +525,8 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, } } -/* Toggle outputs muting */ -static void update_outputs(struct hda_codec *codec) +/* Toggle internal speakers muting */ +static void update_speakers(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int on; @@ -548,10 +538,10 @@ static void update_outputs(struct hda_codec *codec) do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), spec->autocfg.hp_pins, spec->master_mute, true); - if (!spec->automute_speaker) + if (!spec->automute) on = 0; else - on = spec->hp_jack_present | spec->line_jack_present; + on = spec->jack_present | spec->line_jack_present; on |= spec->master_mute; do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), spec->autocfg.speaker_pins, on, false); @@ -561,35 +551,26 @@ static void update_outputs(struct hda_codec *codec) if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) return; - if (!spec->automute_lo) + if (!spec->automute_lines || !spec->automute) on = 0; else - on = spec->hp_jack_present; + on = spec->jack_present; on |= spec->master_mute; do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), spec->autocfg.line_out_pins, on, false); } -static void call_update_outputs(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (spec->automute_hook) - spec->automute_hook(codec); - else - update_outputs(codec); -} - /* standard HP-automute helper */ static void alc_hp_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->hp_jack_present = + if (!spec->automute) + return; + spec->jack_present = detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), spec->autocfg.hp_pins); - if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) - return; - call_update_outputs(codec); + update_speakers(codec); } /* standard line-out-automute helper */ @@ -597,16 +578,12 @@ static void alc_line_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - /* check LO jack only when it's different from HP */ - if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) + if (!spec->automute || !spec->detect_line) return; - spec->line_jack_present = detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), spec->autocfg.line_out_pins); - if (!spec->automute_speaker || !spec->detect_lo) - return; - call_update_outputs(codec); + update_speakers(codec); } #define get_connection_index(codec, mux, nid) \ @@ -804,7 +781,7 @@ static int alc_automute_mode_info(struct snd_kcontrol *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - if (spec->automute_speaker_possible && spec->automute_lo_possible) { + if (spec->automute_hp_lo) { uinfo->value.enumerated.items = 3; texts = texts3; } else { @@ -823,12 +800,13 @@ static int alc_automute_mode_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - unsigned int val = 0; - if (spec->automute_speaker) - val++; - if (spec->automute_lo) - val++; - + unsigned int val; + if (!spec->automute) + val = 0; + else if (!spec->automute_lines) + val = 1; + else + val = 2; ucontrol->value.enumerated.item[0] = val; return 0; } @@ -841,36 +819,28 @@ static int alc_automute_mode_put(struct snd_kcontrol *kcontrol, switch (ucontrol->value.enumerated.item[0]) { case 0: - if (!spec->automute_speaker && !spec->automute_lo) + if (!spec->automute) return 0; - spec->automute_speaker = 0; - spec->automute_lo = 0; + spec->automute = 0; break; case 1: - if (spec->automute_speaker_possible) { - if (!spec->automute_lo && spec->automute_speaker) - return 0; - spec->automute_speaker = 1; - spec->automute_lo = 0; - } else if (spec->automute_lo_possible) { - if (spec->automute_lo) - return 0; - spec->automute_lo = 1; - } else - return -EINVAL; + if (spec->automute && !spec->automute_lines) + return 0; + spec->automute = 1; + spec->automute_lines = 0; break; case 2: - if (!spec->automute_lo_possible || !spec->automute_speaker_possible) + if (!spec->automute_hp_lo) return -EINVAL; - if (spec->automute_speaker && spec->automute_lo) + if (spec->automute && spec->automute_lines) return 0; - spec->automute_speaker = 1; - spec->automute_lo = 1; + spec->automute = 1; + spec->automute_lines = 1; break; default: return -EINVAL; } - call_update_outputs(codec); + update_speakers(codec); return 1; } @@ -907,7 +877,7 @@ static int alc_add_automute_mode_enum(struct hda_codec *codec) * Check the availability of HP/line-out auto-mute; * Set up appropriately if really supported */ -static void alc_init_automute(struct hda_codec *codec) +static void alc_init_auto_hp(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -922,6 +892,8 @@ static void alc_init_automute(struct hda_codec *codec) present++; if (present < 2) /* need two different output types */ return; + if (present == 3) + spec->automute_hp_lo = 1; /* both HP and LO automute */ if (!cfg->speaker_pins[0] && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { @@ -937,8 +909,6 @@ static void alc_init_automute(struct hda_codec *codec) cfg->hp_outs = cfg->line_outs; } - spec->automute_mode = ALC_AUTOMUTE_PIN; - for (i = 0; i < cfg->hp_outs; i++) { hda_nid_t nid = cfg->hp_pins[i]; if (!is_jack_detectable(codec, nid)) @@ -948,32 +918,28 @@ static void alc_init_automute(struct hda_codec *codec) snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT); - spec->detect_hp = 1; - } - - if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { - if (cfg->speaker_outs) - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t nid = cfg->line_out_pins[i]; - if (!is_jack_detectable(codec, nid)) - continue; - snd_printdd("realtek: Enable Line-Out " - "auto-muting on NID 0x%x\n", nid); - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC_FRONT_EVENT); - spec->detect_lo = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + } + if (spec->automute && cfg->line_out_pins[0] && + cfg->speaker_pins[0] && + cfg->line_out_pins[0] != cfg->hp_pins[0] && + cfg->line_out_pins[0] != cfg->speaker_pins[0]) { + for (i = 0; i < cfg->line_outs; i++) { + hda_nid_t nid = cfg->line_out_pins[i]; + if (!is_jack_detectable(codec, nid)) + continue; + snd_printdd("realtek: Enable Line-Out auto-muting " + "on NID 0x%x\n", nid); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC_FRONT_EVENT); + spec->detect_line = 1; } - spec->automute_lo_possible = spec->detect_hp; + spec->automute_lines = spec->detect_line; } - spec->automute_speaker_possible = cfg->speaker_outs && - (spec->detect_hp || spec->detect_lo); - - spec->automute_lo = spec->automute_lo_possible; - spec->automute_speaker = spec->automute_speaker_possible; - - if (spec->automute_speaker_possible || spec->automute_lo_possible) { + if (spec->automute) { /* create a control for automute mode */ alc_add_automute_mode_enum(codec); spec->unsol_event = alc_sku_unsol_event; @@ -1174,7 +1140,7 @@ static void alc_init_auto_mic(struct hda_codec *codec) /* check the availabilities of auto-mute and auto-mic switches */ static void alc_auto_check_switches(struct hda_codec *codec) { - alc_init_automute(codec); + alc_init_auto_hp(codec); alc_init_auto_mic(codec); } @@ -1354,9 +1320,7 @@ static int alc_subsystem_id(struct hda_codec *codec, * 15 : 1 --> enable the function "Mute internal speaker * when the external headphone out jack is plugged" */ - if (!spec->autocfg.hp_pins[0] && - !(spec->autocfg.line_out_pins[0] && - spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) { + if (!spec->autocfg.hp_pins[0]) { hda_nid_t nid; tmp = (ass >> 11) & 0x3; /* HP to chassis */ if (tmp == 0) @@ -1557,15 +1521,6 @@ static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx, coef_val); } -/* a special bypass for COEF 0; read the cached value at the second time */ -static unsigned int alc_get_coef0(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (!spec->coef0) - spec->coef0 = alc_read_coef_idx(codec, 0); - return spec->coef0; -} - /* * Digital I/O handling */ @@ -1604,29 +1559,27 @@ static void alc_auto_init_digital(struct hda_codec *codec) static void alc_auto_parse_digital(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - int i, err, nums; + int i, err; hda_nid_t dig_nid; /* support multiple SPDIFs; the secondary is set up as a slave */ - nums = 0; for (i = 0; i < spec->autocfg.dig_outs; i++) { hda_nid_t conn[4]; err = snd_hda_get_connections(codec, spec->autocfg.dig_out_pins[i], conn, ARRAY_SIZE(conn)); - if (err <= 0) + if (err < 0) continue; dig_nid = conn[0]; /* assume the first element is audio-out */ - if (!nums) { + if (!i) { spec->multiout.dig_out_nid = dig_nid; spec->dig_out_type = spec->autocfg.dig_out_type[0]; } else { spec->multiout.slave_dig_outs = spec->slave_dig_outs; - if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) + if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) break; - spec->slave_dig_outs[nums - 1] = dig_nid; + spec->slave_dig_outs[i - 1] = dig_nid; } - nums++; } if (spec->autocfg.dig_in_pin) { @@ -1831,7 +1784,6 @@ static const char * const alc_slave_vols[] = { "Speaker Playback Volume", "Mono Playback Volume", "Line-Out Playback Volume", - "PCM Playback Volume", NULL, }; @@ -1846,7 +1798,6 @@ static const char * const alc_slave_sws[] = { "Mono Playback Switch", "IEC958 Playback Switch", "Line-Out Playback Switch", - "PCM Playback Switch", NULL, }; @@ -2272,7 +2223,6 @@ static int alc_build_pcms(struct hda_codec *codec) struct alc_spec *spec = codec->spec; struct hda_pcm *info = spec->pcm_rec; const struct hda_pcm_stream *p; - bool have_multi_adcs; int i; codec->num_pcms = 1; @@ -2351,11 +2301,8 @@ static int alc_build_pcms(struct hda_codec *codec) /* If the use of more than one ADC is requested for the current * model, configure a second analog capture-only PCM. */ - have_multi_adcs = (spec->num_adc_nids > 1) && - !spec->dyn_adc_switch && !spec->auto_mic && - (!spec->input_mux || spec->input_mux->num_items > 1); /* Additional Analaog capture for index #2 */ - if (spec->alt_dac_nid || have_multi_adcs) { + if (spec->alt_dac_nid || spec->num_adc_nids > 1) { codec->num_pcms = 3; info = spec->pcm_rec + 2; info->name = spec->stream_name_analog; @@ -2371,7 +2318,7 @@ static int alc_build_pcms(struct hda_codec *codec) alc_pcm_null_stream; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; } - if (have_multi_adcs) { + if (spec->num_adc_nids > 1) { p = spec->stream_analog_alt_capture; if (!p) p = &alc_pcm_analog_alt_capture; @@ -2412,18 +2359,6 @@ static void alc_free_kctls(struct hda_codec *codec) snd_array_free(&spec->kctls); } -static void alc_free_bind_ctls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (spec->bind_ctls.list) { - struct hda_bind_ctls **ctl = spec->bind_ctls.list; - int i; - for (i = 0; i < spec->bind_ctls.used; i++) - kfree(ctl[i]); - } - snd_array_free(&spec->bind_ctls); -} - static void alc_free(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -2434,7 +2369,6 @@ static void alc_free(struct hda_codec *codec) alc_shutup(codec); snd_hda_input_jack_free(codec); alc_free_kctls(codec); - alc_free_bind_ctls(codec); kfree(spec); snd_hda_detach_beep_device(codec); } @@ -2497,47 +2431,6 @@ static int alc_codec_rename(struct hda_codec *codec, const char *name) return 0; } -/* - * Rename codecs appropriately from COEF value - */ -struct alc_codec_rename_table { - unsigned int vendor_id; - unsigned short coef_mask; - unsigned short coef_bits; - const char *name; -}; - -static struct alc_codec_rename_table rename_tbl[] = { - { 0x10ec0269, 0xfff0, 0x3010, "ALC277" }, - { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" }, - { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" }, - { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" }, - { 0x10ec0269, 0xffff, 0xa023, "ALC259" }, - { 0x10ec0269, 0xffff, 0x6023, "ALC281X" }, - { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" }, - { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" }, - { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" }, - { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" }, - { 0x10ec0899, 0x2000, 0x2000, "ALC899" }, - { 0x10ec0892, 0xffff, 0x8020, "ALC661" }, - { 0x10ec0892, 0xffff, 0x8011, "ALC661" }, - { 0x10ec0892, 0xffff, 0x4011, "ALC656" }, - { } /* terminator */ -}; - -static int alc_codec_rename_from_preset(struct hda_codec *codec) -{ - const struct alc_codec_rename_table *p; - - for (p = rename_tbl; p->vendor_id; p++) { - if (p->vendor_id != codec->vendor_id) - continue; - if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits) - return alc_codec_rename(codec, p->name); - } - return 0; -} - /* * Automatic parse of I/O pins from the BIOS configuration */ @@ -2546,15 +2439,11 @@ enum { ALC_CTL_WIDGET_VOL, ALC_CTL_WIDGET_MUTE, ALC_CTL_BIND_MUTE, - ALC_CTL_BIND_VOL, - ALC_CTL_BIND_SW, }; static const struct snd_kcontrol_new alc_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), HDA_BIND_MUTE(NULL, 0, 0, 0), - HDA_BIND_VOL(NULL, 0), - HDA_BIND_SW(NULL, 0), }; /* add dynamic controls */ @@ -2595,14 +2484,13 @@ static int add_control_with_pfx(struct alc_spec *spec, int type, #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) -static const char * const channel_name[4] = { - "Front", "Surround", "CLFE", "Side" -}; - static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, bool can_be_master, int *index) { struct auto_pin_cfg *cfg = &spec->autocfg; + static const char * const chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; *index = 0; if (cfg->line_outs == 1 && !spec->multi_ios && @@ -2625,10 +2513,7 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, return "PCM"; break; } - if (snd_BUG_ON(ch >= ARRAY_SIZE(channel_name))) - return "PCM"; - - return channel_name[ch]; + return chname[ch]; } /* create input playback/capture controls for the given pin */ @@ -2663,6 +2548,7 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec) hda_nid_t *adc_nids = spec->private_adc_nids; hda_nid_t *cap_nids = spec->private_capsrc_nids; int max_nums = ARRAY_SIZE(spec->private_adc_nids); + bool indep_capsrc = false; int i, nums = 0; nid = codec->start_nid; @@ -2684,11 +2570,13 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec) break; if (type == AC_WID_AUD_SEL) { cap_nids[nums] = src; + indep_capsrc = true; break; } n = snd_hda_get_conn_list(codec, src, &list); if (n > 1) { cap_nids[nums] = src; + indep_capsrc = true; break; } else if (n != 1) break; @@ -2889,9 +2777,8 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) if (found_in_nid_list(nid, spec->multiout.dac_nids, spec->multiout.num_dacs)) continue; - if (found_in_nid_list(nid, spec->multiout.hp_out_nid, - ARRAY_SIZE(spec->multiout.hp_out_nid))) - continue; + if (spec->multiout.hp_nid == nid) + continue; if (found_in_nid_list(nid, spec->multiout.extra_out_nid, ARRAY_SIZE(spec->multiout.extra_out_nid))) continue; @@ -2908,29 +2795,6 @@ static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) return 0; } -static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs, - const hda_nid_t *pins, hda_nid_t *dacs) -{ - int i; - - if (num_outs && !dacs[0]) { - dacs[0] = alc_auto_look_for_dac(codec, pins[0]); - if (!dacs[0]) - return 0; - } - - for (i = 1; i < num_outs; i++) - dacs[i] = get_dac_if_single(codec, pins[i]); - for (i = 1; i < num_outs; i++) { - if (!dacs[i]) - dacs[i] = alc_auto_look_for_dac(codec, pins[i]); - } - return 0; -} - -static int alc_auto_fill_multi_ios(struct hda_codec *codec, - unsigned int location); - /* fill in the dac_nids table from the parsed pin configuration */ static int alc_auto_fill_dac_nids(struct hda_codec *codec) { @@ -2942,7 +2806,7 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) again: /* set num_dacs once to full for alc_auto_look_for_dac() */ spec->multiout.num_dacs = cfg->line_outs; - spec->multiout.hp_out_nid[0] = 0; + spec->multiout.hp_nid = 0; spec->multiout.extra_out_nid[0] = 0; memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); spec->multiout.dac_nids = spec->private_dac_nids; @@ -2953,7 +2817,7 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) spec->private_dac_nids[i] = get_dac_if_single(codec, cfg->line_out_pins[i]); if (cfg->hp_outs) - spec->multiout.hp_out_nid[0] = + spec->multiout.hp_nid = get_dac_if_single(codec, cfg->hp_pins[0]); if (cfg->speaker_outs) spec->multiout.extra_out_nid[0] = @@ -2985,58 +2849,24 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); } - if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - /* try to fill multi-io first */ - unsigned int location, defcfg; - int num_pins; - - defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); - location = get_defcfg_location(defcfg); - - num_pins = alc_auto_fill_multi_ios(codec, location); - if (num_pins > 0) { - spec->multi_ios = num_pins; - spec->ext_channel_count = 2; - spec->multiout.num_dacs = num_pins + 1; - } - } - - if (cfg->line_out_type != AUTO_PIN_HP_OUT) - alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins, - spec->multiout.hp_out_nid); - if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) - alc_auto_fill_extra_dacs(codec, cfg->speaker_outs, cfg->speaker_pins, - spec->multiout.extra_out_nid); + if (cfg->hp_outs && !spec->multiout.hp_nid) + spec->multiout.hp_nid = + alc_auto_look_for_dac(codec, cfg->hp_pins[0]); + if (cfg->speaker_outs && !spec->multiout.extra_out_nid[0]) + spec->multiout.extra_out_nid[0] = + alc_auto_look_for_dac(codec, cfg->speaker_pins[0]); return 0; } -static inline unsigned int get_ctl_pos(unsigned int data) -{ - hda_nid_t nid = get_amp_nid_(data); - unsigned int dir = get_amp_direction_(data); - return (nid << 1) | dir; -} - -#define is_ctl_used(bits, data) \ - test_bit(get_ctl_pos(data), bits) -#define mark_ctl_usage(bits, data) \ - set_bit(get_ctl_pos(data), bits) - static int alc_auto_add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, hda_nid_t nid, unsigned int chs) { - struct alc_spec *spec = codec->spec; - unsigned int val; if (!nid) return 0; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT); - if (is_ctl_used(spec->vol_ctls, val) && chs != 2) /* exclude LFE */ - return 0; - mark_ctl_usage(spec->vol_ctls, val); return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx, - val); + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); } #define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \ @@ -3049,7 +2879,6 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, hda_nid_t nid, unsigned int chs) { - struct alc_spec *spec = codec->spec; int wid_type; int type; unsigned long val; @@ -3066,9 +2895,6 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec, type = ALC_CTL_BIND_MUTE; val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT); } - if (is_ctl_used(spec->sw_ctls, val) && chs != 2) /* exclude LFE */ - return 0; - mark_ctl_usage(spec->sw_ctls, val); return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); } @@ -3129,7 +2955,7 @@ static int alc_auto_create_multi_out_ctls(struct hda_codec *codec, sw = alc_look_for_out_mute_nid(codec, pin, dac); vol = alc_look_for_out_vol_nid(codec, pin, dac); name = alc_get_line_out_pfx(spec, i, true, &index); - if (!name || !strcmp(name, "CLFE")) { + if (!name) { /* Center/LFE */ err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1); if (err < 0) @@ -3155,24 +2981,23 @@ static int alc_auto_create_multi_out_ctls(struct hda_codec *codec, return 0; } +/* add playback controls for speaker and HP outputs */ static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac, const char *pfx) + hda_nid_t dac, const char *pfx) { struct alc_spec *spec = codec->spec; hda_nid_t sw, vol; int err; + if (!pin) + return 0; if (!dac) { - unsigned int val; /* the corresponding DAC is already occupied */ if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) return 0; /* no way */ /* create a switch only */ - val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT); - if (is_ctl_used(spec->sw_ctls, val)) - return 0; /* already created */ - mark_ctl_usage(spec->sw_ctls, val); - return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val); + return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); } sw = alc_look_for_out_mute_nid(codec, pin, dac); @@ -3186,112 +3011,20 @@ static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, return 0; } -static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec, - unsigned int nums, - struct hda_ctl_ops *ops) -{ - struct alc_spec *spec = codec->spec; - struct hda_bind_ctls **ctlp, *ctl; - snd_array_init(&spec->bind_ctls, sizeof(ctl), 8); - ctlp = snd_array_new(&spec->bind_ctls); - if (!ctlp) - return NULL; - ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL); - *ctlp = ctl; - if (ctl) - ctl->ops = ops; - return ctl; -} - -/* add playback controls for speaker and HP outputs */ -static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins, - const hda_nid_t *pins, - const hda_nid_t *dacs, - const char *pfx) -{ - struct alc_spec *spec = codec->spec; - struct hda_bind_ctls *ctl; - char name[32]; - int i, n, err; - - if (!num_pins || !pins[0]) - return 0; - - if (num_pins == 1) { - hda_nid_t dac = *dacs; - if (!dac) - dac = spec->multiout.dac_nids[0]; - return alc_auto_create_extra_out(codec, *pins, dac, pfx); - } - - if (dacs[num_pins - 1]) { - /* OK, we have a multi-output system with individual volumes */ - for (i = 0; i < num_pins; i++) { - snprintf(name, sizeof(name), "%s %s", - pfx, channel_name[i]); - err = alc_auto_create_extra_out(codec, pins[i], dacs[i], - name); - if (err < 0) - return err; - } - return 0; - } - - /* Let's create a bind-controls */ - ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_sw); - if (!ctl) - return -ENOMEM; - n = 0; - for (i = 0; i < num_pins; i++) { - if (get_wcaps(codec, pins[i]) & AC_WCAP_OUT_AMP) - ctl->values[n++] = - HDA_COMPOSE_AMP_VAL(pins[i], 3, 0, HDA_OUTPUT); - } - if (n) { - snprintf(name, sizeof(name), "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_BIND_SW, name, 0, (long)ctl); - if (err < 0) - return err; - } - - ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol); - if (!ctl) - return -ENOMEM; - n = 0; - for (i = 0; i < num_pins; i++) { - hda_nid_t vol; - if (!pins[i] || !dacs[i]) - continue; - vol = alc_look_for_out_vol_nid(codec, pins[i], dacs[i]); - if (vol) - ctl->values[n++] = - HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT); - } - if (n) { - snprintf(name, sizeof(name), "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_BIND_VOL, name, 0, (long)ctl); - if (err < 0) - return err; - } - return 0; -} - static int alc_auto_create_hp_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_outs(codec, spec->autocfg.hp_outs, - spec->autocfg.hp_pins, - spec->multiout.hp_out_nid, - "Headphone"); + return alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], + spec->multiout.hp_nid, + "Headphone"); } static int alc_auto_create_speaker_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_outs(codec, spec->autocfg.speaker_outs, - spec->autocfg.speaker_pins, - spec->multiout.extra_out_nid, - "Speaker"); + return alc_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], + spec->multiout.extra_out_nid[0], + "Speaker"); } static void alc_auto_set_output_and_unmute(struct hda_codec *codec, @@ -3348,39 +3081,16 @@ static void alc_auto_init_multi_out(struct hda_codec *codec) static void alc_auto_init_extra_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - int i; - hda_nid_t pin, dac; + hda_nid_t pin; - for (i = 0; i < spec->autocfg.hp_outs; i++) { - if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) - break; - pin = spec->autocfg.hp_pins[i]; - if (!pin) - break; - dac = spec->multiout.hp_out_nid[i]; - if (!dac) { - if (i > 0 && spec->multiout.hp_out_nid[0]) - dac = spec->multiout.hp_out_nid[0]; - else - dac = spec->multiout.dac_nids[0]; - } - alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); - } - for (i = 0; i < spec->autocfg.speaker_outs; i++) { - if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) - break; - pin = spec->autocfg.speaker_pins[i]; - if (!pin) - break; - dac = spec->multiout.extra_out_nid[i]; - if (!dac) { - if (i > 0 && spec->multiout.extra_out_nid[0]) - dac = spec->multiout.extra_out_nid[0]; - else - dac = spec->multiout.dac_nids[0]; - } - alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); - } + pin = spec->autocfg.hp_pins[0]; + if (pin) + alc_auto_set_output_and_unmute(codec, pin, PIN_HP, + spec->multiout.hp_nid); + pin = spec->autocfg.speaker_pins[0]; + if (pin) + alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, + spec->multiout.extra_out_nid[0]); } /* @@ -3391,7 +3101,6 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec, { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t prime_dac = spec->private_dac_nids[0]; int type, i, num_pins = 0; for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { @@ -3419,13 +3128,8 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec, } } spec->multiout.num_dacs = 1; - if (num_pins < 2) { - /* clear up again */ - memset(spec->private_dac_nids, 0, - sizeof(spec->private_dac_nids)); - spec->private_dac_nids[0] = prime_dac; + if (num_pins < 2) return 0; - } return num_pins; } @@ -3511,11 +3215,36 @@ static const struct snd_kcontrol_new alc_auto_channel_mode_enum = { .put = alc_auto_ch_mode_put, }; -static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec, + int (*fill_dac)(struct hda_codec *)) { struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int location, defcfg; + int num_pins; + + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->hp_outs == 1) { + /* use HP as primary out */ + cfg->speaker_outs = cfg->line_outs; + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->line_outs = cfg->hp_outs; + memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); + cfg->hp_outs = 0; + memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); + cfg->line_out_type = AUTO_PIN_HP_OUT; + if (fill_dac) + fill_dac(codec); + } + if (cfg->line_outs != 1 || + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + return 0; - if (spec->multi_ios > 0) { + defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); + location = get_defcfg_location(defcfg); + + num_pins = alc_auto_fill_multi_ios(codec, location); + if (num_pins > 0) { struct snd_kcontrol_new *knew; knew = alc_kcontrol_new(spec); @@ -3525,6 +3254,10 @@ static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) knew->name = kstrdup("Channel Mode", GFP_KERNEL); if (!knew->name) return -ENOMEM; + + spec->multi_ios = num_pins; + spec->ext_channel_count = 2; + spec->multiout.num_dacs = num_pins + 1; } return 0; } @@ -3807,42 +3540,27 @@ static int alc_parse_auto_config(struct hda_codec *codec, const hda_nid_t *ssid_nids) { struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; int err; - err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids, - spec->parse_flags); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + ignore_nids); if (err < 0) return err; - if (!cfg->line_outs) { - if (cfg->dig_outs || cfg->dig_in_pin) { + if (!spec->autocfg.line_outs) { + if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { spec->multiout.max_channels = 2; spec->no_analog = 1; goto dig_only; } return 0; /* can't find valid BIOS pin config */ } - - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && - cfg->line_outs <= cfg->hp_outs) { - /* use HP as primary out */ - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - cfg->line_out_type = AUTO_PIN_HP_OUT; - } - err = alc_auto_fill_dac_nids(codec); if (err < 0) return err; - err = alc_auto_add_multi_channel_mode(codec); + err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids); if (err < 0) return err; - err = alc_auto_create_multi_out_ctls(codec, cfg); + err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; err = alc_auto_create_hp_out(codec); @@ -3945,8 +3663,10 @@ static int patch_alc880(struct hda_codec *codec) if (board_config == ALC_MODEL_AUTO) { /* automatic parse from the BIOS config */ err = alc880_parse_auto_config(codec); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS else if (!err) { printk(KERN_INFO @@ -3971,8 +3691,10 @@ static int patch_alc880(struct hda_codec *codec) if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } @@ -3987,10 +3709,6 @@ static int patch_alc880(struct hda_codec *codec) #endif return 0; - - error: - alc_free(codec); - return err; } @@ -4072,8 +3790,10 @@ static int patch_alc260(struct hda_codec *codec) if (board_config == ALC_MODEL_AUTO) { /* automatic parse from the BIOS config */ err = alc260_parse_auto_config(codec); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS else if (!err) { printk(KERN_INFO @@ -4098,8 +3818,10 @@ static int patch_alc260(struct hda_codec *codec) if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); } @@ -4117,10 +3839,6 @@ static int patch_alc260(struct hda_codec *codec) #endif return 0; - - error: - alc_free(codec); - return err; } @@ -4147,7 +3865,6 @@ enum { PINFIX_LENOVO_Y530, PINFIX_PB_M5210, PINFIX_ACER_ASPIRE_7736, - PINFIX_ASUS_W90V, }; static const struct alc_fixup alc882_fixups[] = { @@ -4179,18 +3896,10 @@ static const struct alc_fixup alc882_fixups[] = { .type = ALC_FIXUP_SKU, .v.sku = ALC_FIXUP_SKU_IGNORE, }, - [PINFIX_ASUS_W90V] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x16, 0x99130110 }, /* fix sequence for CLFE */ - { } - } - }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), - SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", PINFIX_ASUS_W90V), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736), @@ -4237,10 +3946,6 @@ static int patch_alc882(struct hda_codec *codec) break; } - err = alc_codec_rename_from_preset(codec); - if (err < 0) - goto error; - board_config = alc_board_config(codec, ALC882_MODEL_LAST, alc882_models, alc882_cfg_tbl); @@ -4264,8 +3969,10 @@ static int patch_alc882(struct hda_codec *codec) if (board_config == ALC_MODEL_AUTO) { /* automatic parse from the BIOS config */ err = alc882_parse_auto_config(codec); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS else if (!err) { printk(KERN_INFO @@ -4290,8 +3997,10 @@ static int patch_alc882(struct hda_codec *codec) if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } @@ -4310,10 +4019,6 @@ static int patch_alc882(struct hda_codec *codec) #endif return 0; - - error: - alc_free(codec); - return err; } @@ -4418,8 +4123,10 @@ static int patch_alc262(struct hda_codec *codec) if (board_config == ALC_MODEL_AUTO) { /* automatic parse from the BIOS config */ err = alc262_parse_auto_config(codec); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS else if (!err) { printk(KERN_INFO @@ -4444,8 +4151,10 @@ static int patch_alc262(struct hda_codec *codec) if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } @@ -4465,10 +4174,6 @@ static int patch_alc262(struct hda_codec *codec) #endif return 0; - - error: - alc_free(codec); - return err; } /* @@ -4517,9 +4222,14 @@ static int alc268_parse_auto_config(struct hda_codec *codec) /* */ +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS +#include "alc268_quirks.c" +#endif + static int patch_alc268(struct hda_codec *codec) { struct alc_spec *spec; + int board_config; int i, has_beep, err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -4530,10 +4240,38 @@ static int patch_alc268(struct hda_codec *codec) /* ALC268 has no aa-loopback mixer */ - /* automatic parse from the BIOS config */ - err = alc268_parse_auto_config(codec); - if (err < 0) - goto error; + board_config = alc_board_config(codec, ALC268_MODEL_LAST, + alc268_models, alc268_cfg_tbl); + + if (board_config < 0) + board_config = alc_board_codec_sid_config(codec, + ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl); + + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC_MODEL_AUTO; + } + + if (board_config == ALC_MODEL_AUTO) { + /* automatic parse from the BIOS config */ + err = alc268_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS + else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC268_3ST; + } +#endif + } + + if (board_config != ALC_MODEL_AUTO) + setup_preset(codec, &alc268_presets[board_config]); has_beep = 0; for (i = 0; i < spec->num_mixers; i++) { @@ -4545,8 +4283,10 @@ static int patch_alc268(struct hda_codec *codec) if (has_beep) { err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) /* override the amp caps for beep generator */ snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, @@ -4568,16 +4308,13 @@ static int patch_alc268(struct hda_codec *codec) spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; + if (board_config == ALC_MODEL_AUTO) + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); return 0; - - error: - alc_free(codec); - return err; } /* @@ -4671,9 +4408,9 @@ static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) static void alc269_shutup(struct hda_codec *codec) { - if ((alc_get_coef0(codec) & 0x00ff) == 0x017) + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) alc269_toggle_power_output(codec, 0); - if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { alc269_toggle_power_output(codec, 0); msleep(150); } @@ -4682,19 +4419,19 @@ static void alc269_shutup(struct hda_codec *codec) #ifdef CONFIG_PM static int alc269_resume(struct hda_codec *codec) { - if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { alc269_toggle_power_output(codec, 0); msleep(150); } codec->patch_ops.init(codec); - if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { alc269_toggle_power_output(codec, 1); msleep(200); } - if ((alc_get_coef0(codec) & 0x00ff) == 0x018) + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) alc269_toggle_power_output(codec, 1); snd_hda_codec_resume_amp(codec); @@ -4747,46 +4484,6 @@ static void alc269_fixup_pcm_44k(struct hda_codec *codec, spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; } -static void alc269_fixup_stereo_dmic(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - int coef; - - if (action != ALC_FIXUP_ACT_INIT) - return; - /* The digital-mic unit sends PDM (differential signal) instead of - * the standard PCM, thus you can't record a valid mono stream as is. - * Below is a workaround specific to ALC269 to control the dmic - * signal source as mono. - */ - coef = alc_read_coef_idx(codec, 0x07); - alc_write_coef_idx(codec, 0x07, coef | 0x80); -} - -static void alc269_quanta_automute(struct hda_codec *codec) -{ - update_outputs(codec); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x680); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x480); -} - -static void alc269_fixup_quanta_mute(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - if (action != ALC_FIXUP_ACT_PROBE) - return; - spec->automute_hook = alc269_quanta_automute; -} - enum { ALC269_FIXUP_SONY_VAIO, ALC275_FIXUP_SONY_VAIO_GPIO2, @@ -4797,13 +4494,6 @@ enum { ALC275_FIXUP_SONY_HWEQ, ALC271_FIXUP_DMIC, ALC269_FIXUP_PCM_44K, - ALC269_FIXUP_STEREO_DMIC, - ALC269_FIXUP_QUANTA_MUTE, - ALC269_FIXUP_LIFEBOOK, - ALC269_FIXUP_AMIC, - ALC269_FIXUP_DMIC, - ALC269VB_FIXUP_AMIC, - ALC269VB_FIXUP_DMIC, }; static const struct alc_fixup alc269_fixups[] = { @@ -4866,144 +4556,23 @@ static const struct alc_fixup alc269_fixups[] = { .type = ALC_FIXUP_FUNC, .v.func = alc269_fixup_pcm_44k, }, - [ALC269_FIXUP_STEREO_DMIC] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc269_fixup_stereo_dmic, - }, - [ALC269_FIXUP_QUANTA_MUTE] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc269_fixup_quanta_mute, - }, - [ALC269_FIXUP_LIFEBOOK] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x1a, 0x2101103f }, /* dock line-out */ - { 0x1b, 0x23a11040 }, /* dock mic-in */ - { } - }, - .chained = true, - .chain_id = ALC269_FIXUP_QUANTA_MUTE - }, - [ALC269_FIXUP_AMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x0121401f }, /* HP out */ - { 0x18, 0x01a19c20 }, /* mic */ - { 0x19, 0x99a3092f }, /* int-mic */ - { } - }, - }, - [ALC269_FIXUP_DMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x12, 0x99a3092f }, /* int-mic */ - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x0121401f }, /* HP out */ - { 0x18, 0x01a19c20 }, /* mic */ - { } - }, - }, - [ALC269VB_FIXUP_AMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x18, 0x01a19c20 }, /* mic */ - { 0x19, 0x99a3092f }, /* int-mic */ - { 0x21, 0x0121401f }, /* HP out */ - { } - }, - }, - [ALC269_FIXUP_DMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x12, 0x99a3092f }, /* int-mic */ - { 0x14, 0x99130110 }, /* speaker */ - { 0x18, 0x01a19c20 }, /* mic */ - { 0x21, 0x0121401f }, /* HP out */ - { } - }, - }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), - SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), - SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), - -#if 1 - /* Below is a quirk table taken from the old code. - * Basically the device should work as is without the fixup table. - * If BIOS doesn't give a proper info, enable the corresponding - * fixup entry. - */ - SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", - ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_FIXUP_DMIC), - SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_FIXUP_DMIC), - SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_FIXUP_DMIC), -#endif - {} -}; - -static const struct alc_model_fixup alc269_fixup_models[] = { - {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"}, - {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"}, {} }; @@ -5012,23 +4581,23 @@ static int alc269_fill_coef(struct hda_codec *codec) { int val; - if ((alc_get_coef0(codec) & 0x00ff) < 0x015) { + if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) { alc_write_coef_idx(codec, 0xf, 0x960b); alc_write_coef_idx(codec, 0xe, 0x8817); } - if ((alc_get_coef0(codec) & 0x00ff) == 0x016) { + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) { alc_write_coef_idx(codec, 0xf, 0x960b); alc_write_coef_idx(codec, 0xe, 0x8814); } - if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { val = alc_read_coef_idx(codec, 0x04); /* Power up output pin */ alc_write_coef_idx(codec, 0x04, val | (1<<11)); } - if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { val = alc_read_coef_idx(codec, 0xd); if ((val & 0x0c00) >> 10 != 0x1) { /* Capless ramp up clock control */ @@ -5052,10 +4621,15 @@ static int alc269_fill_coef(struct hda_codec *codec) /* */ +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS +#include "alc269_quirks.c" +#endif + static int patch_alc269(struct hda_codec *codec) { struct alc_spec *spec; - int err = 0; + int board_config, coef; + int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -5067,41 +4641,72 @@ static int patch_alc269(struct hda_codec *codec) alc_auto_parse_customize_define(codec); - err = alc_codec_rename_from_preset(codec); - if (err < 0) - goto error; - if (codec->vendor_id == 0x10ec0269) { spec->codec_variant = ALC269_TYPE_ALC269VA; - switch (alc_get_coef0(codec) & 0x00f0) { - case 0x0010: + coef = alc_read_coef_idx(codec, 0); + if ((coef & 0x00f0) == 0x0010) { if (codec->bus->pci->subsystem_vendor == 0x1025 && - spec->cdefine.platform_type == 1) - err = alc_codec_rename(codec, "ALC271X"); + spec->cdefine.platform_type == 1) { + alc_codec_rename(codec, "ALC271X"); + } else if ((coef & 0xf000) == 0x2000) { + alc_codec_rename(codec, "ALC259"); + } else if ((coef & 0xf000) == 0x3000) { + alc_codec_rename(codec, "ALC258"); + } else if ((coef & 0xfff0) == 0x3010) { + alc_codec_rename(codec, "ALC277"); + } else { + alc_codec_rename(codec, "ALC269VB"); + } spec->codec_variant = ALC269_TYPE_ALC269VB; - break; - case 0x0020: - if (codec->bus->pci->subsystem_vendor == 0x17aa && - codec->bus->pci->subsystem_device == 0x21f3) - err = alc_codec_rename(codec, "ALC3202"); + } else if ((coef & 0x00f0) == 0x0020) { + if (coef == 0xa023) + alc_codec_rename(codec, "ALC259"); + else if (coef == 0x6023) + alc_codec_rename(codec, "ALC281X"); + else if (codec->bus->pci->subsystem_vendor == 0x17aa && + codec->bus->pci->subsystem_device == 0x21f3) + alc_codec_rename(codec, "ALC3202"); + else + alc_codec_rename(codec, "ALC269VC"); spec->codec_variant = ALC269_TYPE_ALC269VC; - break; - default: + } else alc_fix_pll_init(codec, 0x20, 0x04, 15); - } - if (err < 0) - goto error; alc269_fill_coef(codec); } - alc_pick_fixup(codec, alc269_fixup_models, - alc269_fixup_tbl, alc269_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + board_config = alc_board_config(codec, ALC269_MODEL_LAST, + alc269_models, alc269_cfg_tbl); - /* automatic parse from the BIOS config */ - err = alc269_parse_auto_config(codec); - if (err < 0) - goto error; + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC_MODEL_AUTO; + } + + if (board_config == ALC_MODEL_AUTO) { + alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + if (board_config == ALC_MODEL_AUTO) { + /* automatic parse from the BIOS config */ + err = alc269_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS + else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC269_BASIC; + } +#endif + } + + if (board_config != ALC_MODEL_AUTO) + setup_preset(codec, &alc269_presets[board_config]); if (!spec->no_analog && !spec->adc_nids) { alc_auto_fill_adc_caps(codec); @@ -5114,8 +4719,10 @@ static int patch_alc269(struct hda_codec *codec) if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); } @@ -5127,7 +4734,8 @@ static int patch_alc269(struct hda_codec *codec) #ifdef CONFIG_PM codec->patch_ops.resume = alc269_resume; #endif - spec->init_hook = alc_auto_init_std; + if (board_config == ALC_MODEL_AUTO) + spec->init_hook = alc_auto_init_std; spec->shutup = alc269_shutup; alc_init_jacks(codec); @@ -5139,10 +4747,6 @@ static int patch_alc269(struct hda_codec *codec) #endif return 0; - - error: - alc_free(codec); - return err; } /* @@ -5190,9 +4794,14 @@ static const struct snd_pci_quirk alc861_fixup_tbl[] = { /* */ +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS +#include "alc861_quirks.c" +#endif + static int patch_alc861(struct hda_codec *codec) { struct alc_spec *spec; + int board_config; int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -5203,13 +4812,39 @@ static int patch_alc861(struct hda_codec *codec) spec->mixer_nid = 0x15; - alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + board_config = alc_board_config(codec, ALC861_MODEL_LAST, + alc861_models, alc861_cfg_tbl); - /* automatic parse from the BIOS config */ - err = alc861_parse_auto_config(codec); - if (err < 0) - goto error; + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC_MODEL_AUTO; + } + + if (board_config == ALC_MODEL_AUTO) { + alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + if (board_config == ALC_MODEL_AUTO) { + /* automatic parse from the BIOS config */ + err = alc861_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS + else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC861_3ST_DIG; + } +#endif + } + + if (board_config != ALC_MODEL_AUTO) + setup_preset(codec, &alc861_presets[board_config]); if (!spec->no_analog && !spec->adc_nids) { alc_auto_fill_adc_caps(codec); @@ -5222,8 +4857,10 @@ static int patch_alc861(struct hda_codec *codec) if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x23); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); } @@ -5232,18 +4869,18 @@ static int patch_alc861(struct hda_codec *codec) alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; + if (board_config == ALC_MODEL_AUTO) { + spec->init_hook = alc_auto_init_std; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->power_hook = alc_power_eapd; +#endif + } #ifdef CONFIG_SND_HDA_POWER_SAVE - spec->power_hook = alc_power_eapd; if (!spec->loopback.amplist) spec->loopback.amplist = alc861_loopbacks; #endif return 0; - - error: - alc_free(codec); - return err; } /* @@ -5265,41 +4902,24 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) } enum { - ALC660VD_FIX_ASUS_GPIO1, - ALC861VD_FIX_DALLAS, + ALC660VD_FIX_ASUS_GPIO1 }; -/* exclude VREF80 */ -static void alc861vd_fixup_dallas(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - if (action == ALC_FIXUP_ACT_PRE_PROBE) { - snd_hda_override_pin_caps(codec, 0x18, 0x00001714); - snd_hda_override_pin_caps(codec, 0x19, 0x0000171c); - } -} - +/* reset GPIO1 */ static const struct alc_fixup alc861vd_fixups[] = { [ALC660VD_FIX_ASUS_GPIO1] = { .type = ALC_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}, { } } }, - [ALC861VD_FIX_DALLAS] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc861vd_fixup_dallas, - }, }; static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS), SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS), {} }; @@ -5311,10 +4931,14 @@ static const struct hda_verb alc660vd_eapd_verbs[] = { /* */ +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS +#include "alc861vd_quirks.c" +#endif + static int patch_alc861vd(struct hda_codec *codec) { struct alc_spec *spec; - int err; + int err, board_config; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -5324,13 +4948,39 @@ static int patch_alc861vd(struct hda_codec *codec) spec->mixer_nid = 0x0b; - alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + board_config = alc_board_config(codec, ALC861VD_MODEL_LAST, + alc861vd_models, alc861vd_cfg_tbl); - /* automatic parse from the BIOS config */ - err = alc861vd_parse_auto_config(codec); - if (err < 0) - goto error; + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC_MODEL_AUTO; + } + + if (board_config == ALC_MODEL_AUTO) { + alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + if (board_config == ALC_MODEL_AUTO) { + /* automatic parse from the BIOS config */ + err = alc861vd_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS + else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC861VD_3ST; + } +#endif + } + + if (board_config != ALC_MODEL_AUTO) + setup_preset(codec, &alc861vd_presets[board_config]); if (codec->vendor_id == 0x10ec0660) { /* always turn on EAPD */ @@ -5348,8 +4998,10 @@ static int patch_alc861vd(struct hda_codec *codec) if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x23); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } @@ -5359,7 +5011,8 @@ static int patch_alc861vd(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; + if (board_config == ALC_MODEL_AUTO) + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) @@ -5367,10 +5020,6 @@ static int patch_alc861vd(struct hda_codec *codec) #endif return 0; - - error: - alc_free(codec); - return err; } /* @@ -5428,14 +5077,6 @@ enum { ALC662_FIXUP_CZC_P10T, ALC662_FIXUP_SKU_IGNORE, ALC662_FIXUP_HP_RP5800, - ALC662_FIXUP_ASUS_MODE1, - ALC662_FIXUP_ASUS_MODE2, - ALC662_FIXUP_ASUS_MODE3, - ALC662_FIXUP_ASUS_MODE4, - ALC662_FIXUP_ASUS_MODE5, - ALC662_FIXUP_ASUS_MODE6, - ALC662_FIXUP_ASUS_MODE7, - ALC662_FIXUP_ASUS_MODE8, }; static const struct alc_fixup alc662_fixups[] = { @@ -5477,204 +5118,37 @@ static const struct alc_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC662_FIXUP_SKU_IGNORE }, - [ALC662_FIXUP_ASUS_MODE1] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x18, 0x01a19c20 }, /* mic */ - { 0x19, 0x99a3092f }, /* int-mic */ - { 0x21, 0x0121401f }, /* HP out */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE2] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x18, 0x01a19820 }, /* mic */ - { 0x19, 0x99a3092f }, /* int-mic */ - { 0x1b, 0x0121401f }, /* HP out */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE3] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x0121441f }, /* HP */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x19, 0x99a3094f }, /* int-mic */ - { 0x21, 0x01211420 }, /* HP2 */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE4] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x16, 0x99130111 }, /* speaker */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x19, 0x99a3094f }, /* int-mic */ - { 0x21, 0x0121441f }, /* HP */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE5] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x0121441f }, /* HP */ - { 0x16, 0x99130111 }, /* speaker */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x19, 0x99a3094f }, /* int-mic */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE6] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x15, 0x01211420 }, /* HP2 */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x19, 0x99a3094f }, /* int-mic */ - { 0x1b, 0x0121441f }, /* HP */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE7] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x17, 0x99130111 }, /* speaker */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x19, 0x99a3094f }, /* int-mic */ - { 0x1b, 0x01214020 }, /* HP */ - { 0x21, 0x0121401f }, /* HP */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, - [ALC662_FIXUP_ASUS_MODE8] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x99130110 }, /* speaker */ - { 0x12, 0x99a30970 }, /* int-mic */ - { 0x15, 0x01214020 }, /* HP */ - { 0x17, 0x99130111 }, /* speaker */ - { 0x18, 0x01a19840 }, /* mic */ - { 0x21, 0x0121401f }, /* HP */ - { } - }, - .chained = true, - .chain_id = ALC662_FIXUP_SKU_IGNORE - }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), - SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), - -#if 0 - /* Below is a quirk table taken from the old code. - * Basically the device should work as is without the fixup table. - * If BIOS doesn't give a proper info, enable the corresponding - * fixup entry. - */ - SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7), - SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7), - SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8), - SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5), - SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4), -#endif {} }; static const struct alc_model_fixup alc662_fixup_models[] = { {.id = ALC272_FIXUP_MARIO, .name = "mario"}, - {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"}, - {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"}, - {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"}, - {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"}, - {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"}, - {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"}, - {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"}, - {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"}, {} }; /* */ +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS +#include "alc662_quirks.c" +#endif + static int patch_alc662(struct hda_codec *codec) { struct alc_spec *spec; - int err = 0; + int err, board_config; + int coef; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) @@ -5684,31 +5158,50 @@ static int patch_alc662(struct hda_codec *codec) spec->mixer_nid = 0x0b; - /* handle multiple HPs as is */ - spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; - alc_auto_parse_customize_define(codec); alc_fix_pll_init(codec, 0x20, 0x04, 15); - err = alc_codec_rename_from_preset(codec); - if (err < 0) - goto error; + coef = alc_read_coef_idx(codec, 0); + if (coef == 0x8020 || coef == 0x8011) + alc_codec_rename(codec, "ALC661"); + else if (coef & (1 << 14) && + codec->bus->pci->subsystem_vendor == 0x1025 && + spec->cdefine.platform_type == 1) + alc_codec_rename(codec, "ALC272X"); + else if (coef == 0x4011) + alc_codec_rename(codec, "ALC656"); + + board_config = alc_board_config(codec, ALC662_MODEL_LAST, + alc662_models, alc662_cfg_tbl); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC_MODEL_AUTO; + } - if ((alc_get_coef0(codec) & (1 << 14)) && - codec->bus->pci->subsystem_vendor == 0x1025 && - spec->cdefine.platform_type == 1) { - if (alc_codec_rename(codec, "ALC272X") < 0) - goto error; + if (board_config == ALC_MODEL_AUTO) { + alc_pick_fixup(codec, alc662_fixup_models, + alc662_fixup_tbl, alc662_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + /* automatic parse from the BIOS config */ + err = alc662_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS + else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC662_3ST_2ch_DIG; + } +#endif } - alc_pick_fixup(codec, alc662_fixup_models, - alc662_fixup_tbl, alc662_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - /* automatic parse from the BIOS config */ - err = alc662_parse_auto_config(codec); - if (err < 0) - goto error; + if (board_config != ALC_MODEL_AUTO) + setup_preset(codec, &alc662_presets[board_config]); if (!spec->no_analog && !spec->adc_nids) { alc_auto_fill_adc_caps(codec); @@ -5721,8 +5214,10 @@ static int patch_alc662(struct hda_codec *codec) if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (err < 0) { + alc_free(codec); + return err; + } switch (codec->vendor_id) { case 0x10ec0662: set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); @@ -5742,7 +5237,8 @@ static int patch_alc662(struct hda_codec *codec) alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; + if (board_config == ALC_MODEL_AUTO) + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); @@ -5753,10 +5249,32 @@ static int patch_alc662(struct hda_codec *codec) #endif return 0; +} - error: - alc_free(codec); - return err; +static int patch_alc888(struct hda_codec *codec) +{ + if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){ + kfree(codec->chip_name); + if (codec->vendor_id == 0x10ec0887) + codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL); + else + codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL); + if (!codec->chip_name) { + alc_free(codec); + return -ENOMEM; + } + return patch_alc662(codec); + } + return patch_alc882(codec); +} + +static int patch_alc899(struct hda_codec *codec) +{ + if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) { + kfree(codec->chip_name); + codec->chip_name = kstrdup("ALC898", GFP_KERNEL); + } + return patch_alc882(codec); } /* @@ -5770,9 +5288,14 @@ static int alc680_parse_auto_config(struct hda_codec *codec) /* */ +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS +#include "alc680_quirks.c" +#endif + static int patch_alc680(struct hda_codec *codec) { struct alc_spec *spec; + int board_config; int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -5783,11 +5306,43 @@ static int patch_alc680(struct hda_codec *codec) /* ALC680 has no aa-loopback mixer */ - /* automatic parse from the BIOS config */ - err = alc680_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; + board_config = alc_board_config(codec, ALC680_MODEL_LAST, + alc680_models, alc680_cfg_tbl); + + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC_MODEL_AUTO; + } + + if (board_config == ALC_MODEL_AUTO) { + /* automatic parse from the BIOS config */ + err = alc680_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS + else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC680_BASE; + } +#endif + } + + if (board_config != ALC_MODEL_AUTO) { + setup_preset(codec, &alc680_presets[board_config]); +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS + spec->stream_analog_capture = &alc680_pcm_analog_auto_capture; +#endif + } + + if (!spec->no_analog && !spec->adc_nids) { + alc_auto_fill_adc_caps(codec); + alc_rebuild_imux_for_auto_mic(codec); + alc_remove_invalid_adc_nids(codec); } if (!spec->no_analog && !spec->cap_mixer) @@ -5796,7 +5351,8 @@ static int patch_alc680(struct hda_codec *codec) spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; + if (board_config == ALC_MODEL_AUTO) + spec->init_hook = alc_auto_init_std; return 0; } @@ -5824,8 +5380,6 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { .patch = patch_alc882 }, { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", .patch = patch_alc662 }, - { .id = 0x10ec0662, .rev = 0x100300, .name = "ALC662 rev3", - .patch = patch_alc662 }, { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, @@ -5838,13 +5392,13 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A", .patch = patch_alc882 }, { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, - { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 }, + { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 }, { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200", .patch = patch_alc882 }, - { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 }, + { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 }, { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 }, { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 }, - { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 }, + { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 }, {} /* terminator */ }; diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index de4c36027cbe..aa376b59c006 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -673,7 +673,6 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, return 0; } -#ifdef CONFIG_SND_HDA_POWER_SAVE static int stac_vrefout_set(struct hda_codec *codec, hda_nid_t nid, unsigned int new_vref) { @@ -697,7 +696,6 @@ static int stac_vrefout_set(struct hda_codec *codec, return 1; } -#endif static unsigned int stac92xx_vref_set(struct hda_codec *codec, hda_nid_t nid, unsigned int new_vref) @@ -2972,9 +2970,8 @@ static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid) { struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; int j, conn_len; - hda_nid_t conn[HDA_MAX_CONNECTIONS], fallback_dac; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; unsigned int wcaps, wtype; conn_len = snd_hda_get_connections(codec, nid, conn, @@ -3002,21 +2999,10 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid) return conn[j]; } } - - /* if all DACs are already assigned, connect to the primary DAC, - unless we're assigning a secondary headphone */ - fallback_dac = spec->multiout.dac_nids[0]; - if (spec->multiout.hp_nid) { - for (j = 0; j < cfg->hp_outs; j++) - if (cfg->hp_pins[j] == nid) { - fallback_dac = spec->multiout.hp_nid; - break; - } - } - + /* if all DACs are already assigned, connect to the primary DAC */ if (conn_len > 1) { for (j = 0; j < conn_len; j++) { - if (conn[j] == fallback_dac) { + if (conn[j] == spec->multiout.dac_nids[0]) { snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, j); break; @@ -3791,10 +3777,9 @@ static int is_dual_headphones(struct hda_codec *codec) } -static int stac92xx_parse_auto_config(struct hda_codec *codec) +static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) { struct sigmatel_spec *spec = codec->spec; - hda_nid_t dig_out = 0, dig_in = 0; int hp_swap = 0; int i, err; @@ -3977,22 +3962,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec) if (spec->multiout.max_channels > 2) spec->surr_switch = 1; - /* find digital out and in converters */ - for (i = codec->start_nid; i < codec->start_nid + codec->num_nodes; i++) { - unsigned int wid_caps = get_wcaps(codec, i); - if (wid_caps & AC_WCAP_DIGITAL) { - switch (get_wcaps_type(wid_caps)) { - case AC_WID_AUD_OUT: - if (!dig_out) - dig_out = i; - break; - case AC_WID_AUD_IN: - if (!dig_in) - dig_in = i; - break; - } - } - } if (spec->autocfg.dig_outs) spec->multiout.dig_out_nid = dig_out; if (dig_in && spec->autocfg.dig_in_pin) @@ -4159,14 +4128,22 @@ static int stac92xx_add_jack(struct hda_codec *codec, #ifdef CONFIG_SND_HDA_INPUT_JACK int def_conf = snd_hda_codec_get_pincfg(codec, nid); int connectivity = get_defcfg_connect(def_conf); + char name[32]; + int err; if (connectivity && connectivity != AC_JACK_PORT_FIXED) return 0; - return snd_hda_input_jack_add(codec, nid, type, NULL); -#else - return 0; + snprintf(name, sizeof(name), "%s at %s %s Jack", + snd_hda_get_jack_type(def_conf), + snd_hda_get_jack_connectivity(def_conf), + snd_hda_get_jack_location(def_conf)); + + err = snd_hda_input_jack_add(codec, nid, type, name); + if (err < 0) + return err; #endif /* CONFIG_SND_HDA_INPUT_JACK */ + return 0; } static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid, @@ -5296,7 +5273,7 @@ static int patch_stac925x(struct hda_codec *codec) spec->capvols = stac925x_capvols; spec->capsws = stac925x_capsws; - err = stac92xx_parse_auto_config(codec); + err = stac92xx_parse_auto_config(codec, 0x8, 0x7); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -5437,7 +5414,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec) spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); spec->pwr_nids = stac92hd73xx_pwr_nids; - err = stac92xx_parse_auto_config(codec); + err = stac92xx_parse_auto_config(codec, 0x25, 0x27); if (!err) { if (spec->board_config < 0) { @@ -5606,7 +5583,9 @@ static void stac92hd8x_fill_auto_spec(struct hda_codec *codec) static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; + hda_nid_t conn[STAC92HD83_DAC_COUNT + 1]; int err; + int num_dacs; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -5646,8 +5625,25 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) stac92xx_set_config_regs(codec, stac92hd83xxx_brd_tbl[spec->board_config]); - if (spec->board_config != STAC_92HD83XXX_PWR_REF) + switch (codec->vendor_id) { + case 0x111d76d1: + case 0x111d76d9: + case 0x111d76e5: + case 0x111d7666: + case 0x111d7667: + case 0x111d7668: + case 0x111d7669: + case 0x111d76e3: + case 0x111d7604: + case 0x111d76d4: + case 0x111d7605: + case 0x111d76d5: + case 0x111d76e7: + if (spec->board_config == STAC_92HD83XXX_PWR_REF) + break; spec->num_pwrs = 0; + break; + } codec->patch_ops = stac92xx_patch_ops; @@ -5674,7 +5670,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) } #endif - err = stac92xx_parse_auto_config(codec); + err = stac92xx_parse_auto_config(codec, 0x1d, 0); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -5690,6 +5686,22 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) return err; } + /* docking output support */ + num_dacs = snd_hda_get_connections(codec, 0xF, + conn, STAC92HD83_DAC_COUNT + 1) - 1; + /* skip non-DAC connections */ + while (num_dacs >= 0 && + (get_wcaps_type(get_wcaps(codec, conn[num_dacs])) + != AC_WID_AUD_OUT)) + num_dacs--; + /* set port E and F to select the last DAC */ + if (num_dacs >= 0) { + snd_hda_codec_write_cache(codec, 0xE, 0, + AC_VERB_SET_CONNECT_SEL, num_dacs); + snd_hda_codec_write_cache(codec, 0xF, 0, + AC_VERB_SET_CONNECT_SEL, num_dacs); + } + codec->proc_widget_hook = stac92hd_proc_hook; return 0; @@ -5995,7 +6007,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; - err = stac92xx_parse_auto_config(codec); + err = stac92xx_parse_auto_config(codec, 0x21, 0); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -6104,7 +6116,7 @@ static int patch_stac922x(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; - err = stac92xx_parse_auto_config(codec); + err = stac92xx_parse_auto_config(codec, 0x08, 0x09); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -6229,7 +6241,7 @@ static int patch_stac927x(struct hda_codec *codec) spec->aloopback_shift = 0; spec->eapd_switch = 1; - err = stac92xx_parse_auto_config(codec); + err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -6354,7 +6366,7 @@ static int patch_stac9205(struct hda_codec *codec) break; } - err = stac92xx_parse_auto_config(codec); + err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -6459,7 +6471,7 @@ static int patch_stac9872(struct hda_codec *codec) spec->capvols = stac9872_capvols; spec->capsws = stac9872_capsws; - err = stac92xx_parse_auto_config(codec); + err = stac92xx_parse_auto_config(codec, 0x10, 0x12); if (err < 0) { stac92xx_free(codec); return -EINVAL; @@ -6559,23 +6571,10 @@ static const struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx }, { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx }, { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx }, - { .id = 0x111d76df, .name = "92HD93BXX", .patch = patch_stac92hd83xxx}, { .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx}, { .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx}, { .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx}, { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76e8, .name = "92HD66B1X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76e9, .name = "92HD66B2X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76ea, .name = "92HD66B3X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76eb, .name = "92HD66C1X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76ec, .name = "92HD66C2X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76ed, .name = "92HD66C3X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76ee, .name = "92HD66B1X3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76ef, .name = "92HD66B2X3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76f0, .name = "92HD66B3X3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76f1, .name = "92HD66C1X3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76f2, .name = "92HD66C2X3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76f3, .name = "92HD66C3/65", .patch = patch_stac92hd83xxx}, {} /* terminator */ }; diff --git a/trunk/sound/pci/hda/patch_via.c b/trunk/sound/pci/hda/patch_via.c index 0b020a93a8ed..84d8798bf33a 100644 --- a/trunk/sound/pci/hda/patch_via.c +++ b/trunk/sound/pci/hda/patch_via.c @@ -1506,49 +1506,39 @@ static int via_build_pcms(struct hda_codec *codec) struct via_spec *spec = codec->spec; struct hda_pcm *info = spec->pcm_rec; - codec->num_pcms = 0; + codec->num_pcms = 1; codec->pcm_info = info; - if (spec->multiout.num_dacs || spec->num_adc_nids) { - snprintf(spec->stream_name_analog, - sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); - info->name = spec->stream_name_analog; + snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), + "%s Analog", codec->chip_name); + info->name = spec->stream_name_analog; - if (spec->multiout.num_dacs) { - if (!spec->stream_analog_playback) - spec->stream_analog_playback = - &via_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - } + if (!spec->stream_analog_playback) + spec->stream_analog_playback = &via_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + *spec->stream_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->multiout.dac_nids[0]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = + spec->multiout.max_channels; - if (!spec->stream_analog_capture) { - if (spec->dyn_adc_switch) - spec->stream_analog_capture = - &via_pcm_dyn_adc_analog_capture; - else - spec->stream_analog_capture = - &via_pcm_analog_capture; - } - if (spec->num_adc_nids) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - *spec->stream_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->adc_nids[0]; - if (!spec->dyn_adc_switch) - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids; - } - codec->num_pcms++; - info++; + if (!spec->stream_analog_capture) { + if (spec->dyn_adc_switch) + spec->stream_analog_capture = + &via_pcm_dyn_adc_analog_capture; + else + spec->stream_analog_capture = &via_pcm_analog_capture; } + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + *spec->stream_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + if (!spec->dyn_adc_switch) + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = + spec->num_adc_nids; if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + codec->num_pcms++; + info++; snprintf(spec->stream_name_digital, sizeof(spec->stream_name_digital), "%s Digital", codec->chip_name); @@ -1572,19 +1562,17 @@ static int via_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; } - codec->num_pcms++; - info++; } if (spec->hp_dac_nid) { + codec->num_pcms++; + info++; snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp), "%s HP", codec->chip_name); info->name = spec->stream_name_hp; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->hp_dac_nid; - codec->num_pcms++; - info++; } return 0; } @@ -2096,7 +2084,7 @@ static int via_auto_create_speaker_ctls(struct hda_codec *codec) struct via_spec *spec = codec->spec; struct nid_path *path; bool check_dac; - hda_nid_t pin, dac = 0; + hda_nid_t pin, dac; int err; pin = spec->autocfg.speaker_pins[0]; @@ -3700,8 +3688,13 @@ static const struct hda_verb vt1812_init_verbs[] = { static void set_widgets_power_state_vt1812(struct hda_codec *codec) { struct via_spec *spec = codec->spec; + int imux_is_smixer = + snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; unsigned int parm; unsigned int present; + /* MUX10 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; /* inputs */ /* PW 5/6/7 (29h/2ah/2bh) */ parm = AC_PWRST_D3; diff --git a/trunk/sound/pci/ice1712/ice1712.c b/trunk/sound/pci/ice1712/ice1712.c index 8531b983f3af..0ccc0eb75775 100644 --- a/trunk/sound/pci/ice1712/ice1712.c +++ b/trunk/sound/pci/ice1712/ice1712.c @@ -2748,9 +2748,8 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, if (!c->no_mpu401) { err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, ICEREG(ice, MPU1_CTRL), - c->mpu401_1_info_flags | - MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, - -1, &ice->rmidi[0]); + (c->mpu401_1_info_flags | MPU401_INFO_INTEGRATED), + ice->irq, 0, &ice->rmidi[0]); if (err < 0) { snd_card_free(card); return err; @@ -2765,9 +2764,8 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, /* 2nd port used */ err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712, ICEREG(ice, MPU2_CTRL), - c->mpu401_2_info_flags | - MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, - -1, &ice->rmidi[1]); + (c->mpu401_2_info_flags | MPU401_INFO_INTEGRATED), + ice->irq, 0, &ice->rmidi[1]); if (err < 0) { snd_card_free(card); diff --git a/trunk/sound/pci/intel8x0.c b/trunk/sound/pci/intel8x0.c index 45b2055f5a76..6a5b387b97fd 100644 --- a/trunk/sound/pci/intel8x0.c +++ b/trunk/sound/pci/intel8x0.c @@ -42,12 +42,6 @@ #include #include -#ifdef CONFIG_KVM_GUEST -#include -#else -#define kvm_para_available() (0) -#endif - MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455"); MODULE_LICENSE("GPL"); @@ -83,7 +77,6 @@ static int buggy_semaphore; static int buggy_irq = -1; /* auto-check */ static int xbox; static int spdif_aclink = -1; -static int inside_vm = -1; module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard."); @@ -101,8 +94,6 @@ module_param(xbox, bool, 0444); MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection."); module_param(spdif_aclink, int, 0444); MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); -module_param(inside_vm, bool, 0444); -MODULE_PARM_DESC(inside_vm, "KVM/Parallels optimization."); /* just for backward compatibility */ static int enable; @@ -409,7 +400,6 @@ struct intel8x0 { unsigned buggy_irq: 1; /* workaround for buggy mobos */ unsigned xbox: 1; /* workaround for Xbox AC'97 detection */ unsigned buggy_semaphore: 1; /* workaround for buggy codec semaphore */ - unsigned inside_vm: 1; /* enable VM optimization */ int spdif_idx; /* SPDIF BAR index; *_SPBAR or -1 if use PCMOUT */ unsigned int sdm_saved; /* SDM reg value */ @@ -1075,11 +1065,8 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs udelay(10); continue; } - if (civ != igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV)) - continue; - if (chip->inside_vm) - break; - if (ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) + if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) && + ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) break; } while (timeout--); ptr = ichdev->last_pos; @@ -2997,10 +2984,6 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, if (xbox) chip->xbox = 1; - chip->inside_vm = inside_vm; - if (inside_vm) - printk(KERN_INFO "intel8x0: enable KVM optimization\n"); - if (pci->vendor == PCI_VENDOR_ID_INTEL && pci->device == PCI_DEVICE_ID_INTEL_440MX) chip->fix_nocache = 1; /* enable workaround */ @@ -3243,14 +3226,6 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, buggy_irq = 0; } - if (inside_vm < 0) { - /* detect KVM and Parallels virtual environments */ - inside_vm = kvm_para_available(); -#if defined(__i386__) || defined(__x86_64__) - inside_vm = inside_vm || boot_cpu_has(X86_FEATURE_HYPERVISOR); -#endif - } - if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, &chip)) < 0) { snd_card_free(card); diff --git a/trunk/sound/pci/maestro3.c b/trunk/sound/pci/maestro3.c index 2fd4bf2d6653..0378126e6272 100644 --- a/trunk/sound/pci/maestro3.c +++ b/trunk/sound/pci/maestro3.c @@ -2820,8 +2820,8 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) /* TODO enable MIDI IRQ and I/O */ err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401, chip->iobase + MPU401_DATA_PORT, - MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, - -1, &chip->rmidi); + MPU401_INFO_INTEGRATED, + chip->irq, 0, &chip->rmidi); if (err < 0) printk(KERN_WARNING "maestro3: no MIDI support.\n"); #endif diff --git a/trunk/sound/pci/oxygen/oxygen_lib.c b/trunk/sound/pci/oxygen/oxygen_lib.c index 53e5508abcbf..82311fcb86f6 100644 --- a/trunk/sound/pci/oxygen/oxygen_lib.c +++ b/trunk/sound/pci/oxygen/oxygen_lib.c @@ -678,15 +678,15 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, goto err_card; if (chip->model.device_config & (MIDI_OUTPUT | MIDI_INPUT)) { - unsigned int info_flags = - MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK; + unsigned int info_flags = MPU401_INFO_INTEGRATED; if (chip->model.device_config & MIDI_OUTPUT) info_flags |= MPU401_INFO_OUTPUT; if (chip->model.device_config & MIDI_INPUT) info_flags |= MPU401_INFO_INPUT; err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, chip->addr + OXYGEN_MPU401, - info_flags, -1, &chip->midi); + info_flags, 0, 0, + &chip->midi); if (err < 0) goto err_card; } diff --git a/trunk/sound/pci/oxygen/xonar_pcm179x.c b/trunk/sound/pci/oxygen/xonar_pcm179x.c index 8433aa7c3d75..32d096c98f5b 100644 --- a/trunk/sound/pci/oxygen/xonar_pcm179x.c +++ b/trunk/sound/pci/oxygen/xonar_pcm179x.c @@ -1074,7 +1074,6 @@ static const struct oxygen_model model_xonar_st = { .device_config = PLAYBACK_0_TO_I2S | PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_2 | - CAPTURE_1_FROM_SPDIF | AC97_FMIC_SWITCH, .dac_channels_pcm = 2, .dac_channels_mixer = 2, diff --git a/trunk/sound/pci/riptide/riptide.c b/trunk/sound/pci/riptide/riptide.c index 88cc776aa38b..e34ae14908b3 100644 --- a/trunk/sound/pci/riptide/riptide.c +++ b/trunk/sound/pci/riptide/riptide.c @@ -2109,7 +2109,7 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) val = mpu_port[dev]; pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, val); err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE, - val, MPU401_INFO_IRQ_HOOK, -1, + val, 0, chip->irq, 0, &chip->rmidi); if (err < 0) snd_printk(KERN_WARNING diff --git a/trunk/sound/pci/rme9652/hdsp.c b/trunk/sound/pci/rme9652/hdsp.c index f74220292254..1c6d1e1c27c1 100644 --- a/trunk/sound/pci/rme9652/hdsp.c +++ b/trunk/sound/pci/rme9652/hdsp.c @@ -151,7 +151,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); #define HDSP_PROGRAM 0x020 #define HDSP_CONFIG_MODE_0 0x040 #define HDSP_CONFIG_MODE_1 0x080 -#define HDSP_VERSION_BIT (0x100 | HDSP_S_LOAD) +#define HDSP_VERSION_BIT 0x100 #define HDSP_BIGENDIAN_MODE 0x200 #define HDSP_RD_MULTIPLE 0x400 #define HDSP_9652_ENABLE_MIXER 0x800 diff --git a/trunk/sound/pci/rme9652/hdspm.c b/trunk/sound/pci/rme9652/hdspm.c index 15a6c3b9bc9a..6edc67ced905 100644 --- a/trunk/sound/pci/rme9652/hdspm.c +++ b/trunk/sound/pci/rme9652/hdspm.c @@ -520,9 +520,16 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) +/* revisions >= 230 indicate AES32 card */ +#define HDSPM_MADI_ANCIENT_REV 204 +#define HDSPM_MADI_OLD_REV 207 +#define HDSPM_MADI_REV 210 #define HDSPM_RAYDAT_REV 211 #define HDSPM_AIO_REV 212 #define HDSPM_MADIFACE_REV 213 +#define HDSPM_AES_REV 240 +#define HDSPM_AES32_REV 234 +#define HDSPM_AES32_OLD_REV 233 /* speed factor modes */ #define HDSPM_SPEED_SINGLE 0 @@ -1234,30 +1241,10 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) return rate; } -/* return latency in samples per period */ -static int hdspm_get_latency(struct hdspm *hdspm) -{ - int n; - - n = hdspm_decode_latency(hdspm->control_register); - - /* Special case for new RME cards with 32 samples period size. - * The three latency bits in the control register - * (HDSP_LatencyMask) encode latency values of 64 samples as - * 0, 128 samples as 1 ... 4096 samples as 6. For old cards, 7 - * denotes 8192 samples, but on new cards like RayDAT or AIO, - * it corresponds to 32 samples. - */ - if ((7 == n) && (RayDAT == hdspm->io_type || AIO == hdspm->io_type)) - n = -1; - - return 1 << (n + 6); -} - /* Latency function */ static inline void hdspm_compute_period_size(struct hdspm *hdspm) { - hdspm->period_bytes = 4 * hdspm_get_latency(hdspm); + hdspm->period_bytes = 1 << ((hdspm_decode_latency(hdspm->control_register) + 8)); } @@ -1316,27 +1303,12 @@ static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames) spin_lock_irq(&s->lock); - if (32 == frames) { - /* Special case for new RME cards like RayDAT/AIO which - * support period sizes of 32 samples. Since latency is - * encoded in the three bits of HDSP_LatencyMask, we can only - * have values from 0 .. 7. While 0 still means 64 samples and - * 6 represents 4096 samples on all cards, 7 represents 8192 - * on older cards and 32 samples on new cards. - * - * In other words, period size in samples is calculated by - * 2^(n+6) with n ranging from 0 .. 7. - */ - n = 7; - } else { - frames >>= 7; - n = 0; - while (frames) { - n++; - frames >>= 1; - } + frames >>= 7; + n = 0; + while (frames) { + n++; + frames >>= 1; } - s->control_register &= ~HDSPM_LatencyMask; s->control_register |= hdspm_encode_latency(n); @@ -1367,10 +1339,6 @@ static u64 hdspm_calc_dds_value(struct hdspm *hdspm, u64 period) break; case MADIface: freq_const = 131072000000000ULL; - break; - default: - snd_BUG(); - return 0; } return div_u64(freq_const, period); @@ -1388,19 +1356,16 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) switch (hdspm->io_type) { case MADIface: - n = 131072000000000ULL; /* 125 MHz */ - break; + n = 131072000000000ULL; /* 125 MHz */ + break; case MADI: case AES32: - n = 110069313433624ULL; /* 105 MHz */ - break; + n = 110069313433624ULL; /* 105 MHz */ + break; case RayDAT: case AIO: - n = 104857600000000ULL; /* 100 MHz */ - break; - default: - snd_BUG(); - return; + n = 104857600000000ULL; /* 100 MHz */ + break; } n = div_u64(n, rate); @@ -4829,7 +4794,8 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, snd_iprintf(buffer, "--- Settings ---\n"); - x = hdspm_get_latency(hdspm); + x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & + HDSPM_LatencyMask)); snd_iprintf(buffer, "Size (Latency): %d samples (2 periods of %lu bytes)\n", @@ -4992,7 +4958,8 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, snd_iprintf(buffer, "--- Settings ---\n"); - x = hdspm_get_latency(hdspm); + x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & + HDSPM_LatencyMask)); snd_iprintf(buffer, "Size (Latency): %d samples (2 periods of %lu bytes)\n", @@ -5698,6 +5665,19 @@ static int snd_hdspm_prepare(struct snd_pcm_substream *substream) return 0; } +static unsigned int period_sizes_old[] = { + 64, 128, 256, 512, 1024, 2048, 4096 +}; + +static unsigned int period_sizes_new[] = { + 32, 64, 128, 256, 512, 1024, 2048, 4096 +}; + +/* RayDAT and AIO always have a buffer of 16384 samples per channel */ +static unsigned int raydat_aio_buffer_sizes[] = { + 16384 +}; + static struct snd_pcm_hardware snd_hdspm_playback_subinfo = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -5716,8 +5696,8 @@ static struct snd_pcm_hardware snd_hdspm_playback_subinfo = { .channels_max = HDSPM_MAX_CHANNELS, .buffer_bytes_max = HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, - .period_bytes_min = (32 * 4), - .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, + .period_bytes_min = (64 * 4), + .period_bytes_max = (4096 * 4) * HDSPM_MAX_CHANNELS, .periods_min = 2, .periods_max = 512, .fifo_size = 0 @@ -5741,13 +5721,31 @@ static struct snd_pcm_hardware snd_hdspm_capture_subinfo = { .channels_max = HDSPM_MAX_CHANNELS, .buffer_bytes_max = HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, - .period_bytes_min = (32 * 4), - .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, + .period_bytes_min = (64 * 4), + .period_bytes_max = (4096 * 4) * HDSPM_MAX_CHANNELS, .periods_min = 2, .periods_max = 512, .fifo_size = 0 }; +static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes_old = { + .count = ARRAY_SIZE(period_sizes_old), + .list = period_sizes_old, + .mask = 0 +}; + +static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes_new = { + .count = ARRAY_SIZE(period_sizes_new), + .list = period_sizes_new, + .mask = 0 +}; + +static struct snd_pcm_hw_constraint_list hw_constraints_raydat_io_buffer = { + .count = ARRAY_SIZE(raydat_aio_buffer_sizes), + .list = raydat_aio_buffer_sizes, + .mask = 0 +}; + static int snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -5948,29 +5946,26 @@ static int snd_hdspm_playback_open(struct snd_pcm_substream *substream) spin_unlock_irq(&hdspm->lock); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); switch (hdspm->io_type) { case AIO: case RayDAT: - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - 32, 4096); - /* RayDAT & AIO have a fixed buffer of 16384 samples per channel */ - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - 16384, 16384); + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + &hw_constraints_period_sizes_new); + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + &hw_constraints_raydat_io_buffer); + break; default: - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - 64, 8192); - break; + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + &hw_constraints_period_sizes_old); } if (AES32 == hdspm->io_type) { - runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdspm_hw_constraints_aes32_sample_rates); } else { @@ -6023,28 +6018,24 @@ static int snd_hdspm_capture_open(struct snd_pcm_substream *substream) spin_unlock_irq(&hdspm->lock); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); - switch (hdspm->io_type) { case AIO: case RayDAT: - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - 32, 4096); - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - 16384, 16384); - break; + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + &hw_constraints_period_sizes_new); + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + &hw_constraints_raydat_io_buffer); + break; default: - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - 64, 8192); - break; + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + &hw_constraints_period_sizes_old); } if (AES32 == hdspm->io_type) { - runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdspm_hw_constraints_aes32_sample_rates); } else { @@ -6090,7 +6081,7 @@ static inline int copy_u32_le(void __user *dest, void __iomem *src) } static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long __user arg) { void __user *argp = (void __user *)arg; struct hdspm *hdspm = hw->private_data; @@ -6215,13 +6206,11 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, info.line_out = hdspm_line_out(hdspm); info.passthru = 0; spin_unlock_irq(&hdspm->lock); - if (copy_to_user(argp, &info, sizeof(info))) + if (copy_to_user((void __user *) arg, &info, sizeof(info))) return -EFAULT; break; case SNDRV_HDSPM_IOCTL_GET_STATUS: - memset(&status, 0, sizeof(status)); - status.card_type = hdspm->io_type; status.autosync_source = hdspm_autosync_ref(hdspm); @@ -6246,7 +6235,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, status.card_specific.madi.madi_input = (statusregister & HDSPM_AB_int) ? 1 : 0; status.card_specific.madi.channel_format = - (statusregister & HDSPM_RX_64ch) ? 1 : 0; + (statusregister & HDSPM_TX_64ch) ? 1 : 0; /* TODO: Mac driver sets it when f_s>48kHz */ status.card_specific.madi.frame_format = 0; @@ -6254,15 +6243,13 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, break; } - if (copy_to_user(argp, &status, sizeof(status))) + if (copy_to_user((void __user *) arg, &status, sizeof(status))) return -EFAULT; break; case SNDRV_HDSPM_IOCTL_GET_VERSION: - memset(&hdspm_version, 0, sizeof(hdspm_version)); - hdspm_version.card_type = hdspm->io_type; strncpy(hdspm_version.cardname, hdspm->card_name, sizeof(hdspm_version.cardname)); @@ -6273,13 +6260,13 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, if (hdspm->tco) hdspm_version.addons |= HDSPM_ADDON_TCO; - if (copy_to_user(argp, &hdspm_version, + if (copy_to_user((void __user *) arg, &hdspm_version, sizeof(hdspm_version))) return -EFAULT; break; case SNDRV_HDSPM_IOCTL_GET_MIXER: - if (copy_from_user(&mixer, argp, sizeof(mixer))) + if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer))) return -EFAULT; if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer, sizeof(struct hdspm_mixer))) @@ -6496,6 +6483,13 @@ static int __devinit snd_hdspm_create(struct snd_card *card, strcpy(card->driver, "HDSPM"); switch (hdspm->firmware_rev) { + case HDSPM_MADI_REV: + case HDSPM_MADI_OLD_REV: + case HDSPM_MADI_ANCIENT_REV: + hdspm->io_type = MADI; + hdspm->card_name = "RME MADI"; + hdspm->midiPorts = 3; + break; case HDSPM_RAYDAT_REV: hdspm->io_type = RayDAT; hdspm->card_name = "RME RayDAT"; @@ -6511,25 +6505,17 @@ static int __devinit snd_hdspm_create(struct snd_card *card, hdspm->card_name = "RME MADIface"; hdspm->midiPorts = 1; break; + case HDSPM_AES_REV: + case HDSPM_AES32_REV: + case HDSPM_AES32_OLD_REV: + hdspm->io_type = AES32; + hdspm->card_name = "RME AES32"; + hdspm->midiPorts = 2; + break; default: - if ((hdspm->firmware_rev == 0xf0) || - ((hdspm->firmware_rev >= 0xe6) && - (hdspm->firmware_rev <= 0xea))) { - hdspm->io_type = AES32; - hdspm->card_name = "RME AES32"; - hdspm->midiPorts = 2; - } else if ((hdspm->firmware_rev == 0xd5) || - ((hdspm->firmware_rev >= 0xc8) && - (hdspm->firmware_rev <= 0xcf))) { - hdspm->io_type = MADI; - hdspm->card_name = "RME MADI"; - hdspm->midiPorts = 3; - } else { - snd_printk(KERN_ERR - "HDSPM: unknown firmware revision %x\n", + snd_printk(KERN_ERR "HDSPM: unknown firmware revision %x\n", hdspm->firmware_rev); - return -ENODEV; - } + return -ENODEV; } err = pci_enable_device(pci); diff --git a/trunk/sound/pci/sis7019.c b/trunk/sound/pci/sis7019.c index 5ffb20b18786..bcf61524a13f 100644 --- a/trunk/sound/pci/sis7019.c +++ b/trunk/sound/pci/sis7019.c @@ -1234,7 +1234,7 @@ static int sis_resume(struct pci_dev *pci) goto error; } - if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED, + if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, KBUILD_MODNAME, sis)) { printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq); goto error; @@ -1340,7 +1340,7 @@ static int __devinit sis_chip_create(struct snd_card *card, if (rc) goto error_out_cleanup; - if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED, + if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, KBUILD_MODNAME, sis)) { printk(KERN_ERR "unable to allocate irq %d\n", sis->irq); goto error_out_cleanup; diff --git a/trunk/sound/pci/sonicvibes.c b/trunk/sound/pci/sonicvibes.c index c5008166cf1f..2571a67b389a 100644 --- a/trunk/sound/pci/sonicvibes.c +++ b/trunk/sound/pci/sonicvibes.c @@ -1493,10 +1493,9 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci, return err; } if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES, - sonic->midi_port, - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &midi_uart)) < 0) { + sonic->midi_port, MPU401_INFO_INTEGRATED, + sonic->irq, 0, + &midi_uart)) < 0) { snd_card_free(card); return err; } diff --git a/trunk/sound/pci/trident/trident.c b/trunk/sound/pci/trident/trident.c index 5e707effdc7c..d8a128f6fc02 100644 --- a/trunk/sound/pci/trident/trident.c +++ b/trunk/sound/pci/trident/trident.c @@ -148,9 +148,8 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, if (trident->device != TRIDENT_DEVICE_ID_SI7018 && (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, trident->midi_port, - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &trident->rmidi)) < 0) { + MPU401_INFO_INTEGRATED, + trident->irq, 0, &trident->rmidi)) < 0) { snd_card_free(card); return err; } diff --git a/trunk/sound/pci/via82xx.c b/trunk/sound/pci/via82xx.c index c3656fffdb50..f03fd620a2a0 100644 --- a/trunk/sound/pci/via82xx.c +++ b/trunk/sound/pci/via82xx.c @@ -1175,7 +1175,6 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev, struct snd_pcm_runtime *runtime = substream->runtime; int err; struct via_rate_lock *ratep; - bool use_src = false; runtime->hw = snd_via82xx_hw; @@ -1197,7 +1196,6 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev, SNDRV_PCM_RATE_8000_48000); runtime->hw.rate_min = 8000; runtime->hw.rate_max = 48000; - use_src = true; } else if (! ratep->rate) { int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; runtime->hw.rates = chip->ac97->rates[idx]; @@ -1214,12 +1212,6 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev, if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; - if (use_src) { - err = snd_pcm_hw_rule_noresample(runtime, 48000); - if (err < 0) - return err; - } - runtime->private_data = viadev; viadev->substream = substream; @@ -2076,9 +2068,8 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip) pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg); if (chip->mpu_res) { if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A, - mpu_port, MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, -1, - &chip->rmidi) < 0) { + mpu_port, MPU401_INFO_INTEGRATED, + chip->irq, 0, &chip->rmidi) < 0) { printk(KERN_WARNING "unable to initialize MPU-401" " at 0x%lx, skipping\n", mpu_port); legacy &= ~VIA_FUNC_ENABLE_MIDI; diff --git a/trunk/sound/pci/ymfpci/ymfpci.c b/trunk/sound/pci/ymfpci/ymfpci.c index 3253b04da184..511d57653124 100644 --- a/trunk/sound/pci/ymfpci/ymfpci.c +++ b/trunk/sound/pci/ymfpci/ymfpci.c @@ -305,9 +305,8 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, if (chip->mpu_res) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, mpu_port[dev], - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &chip->rawmidi)) < 0) { + MPU401_INFO_INTEGRATED, + pci->irq, 0, &chip->rawmidi)) < 0) { printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]); legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */ pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); diff --git a/trunk/sound/pci/ymfpci/ymfpci_main.c b/trunk/sound/pci/ymfpci/ymfpci_main.c index 66ea71b2a70d..f3260e658b8a 100644 --- a/trunk/sound/pci/ymfpci/ymfpci_main.c +++ b/trunk/sound/pci/ymfpci/ymfpci_main.c @@ -897,18 +897,6 @@ static int snd_ymfpci_playback_open_1(struct snd_pcm_substream *substream) struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ymfpci_pcm *ypcm; - int err; - - runtime->hw = snd_ymfpci_playback; - /* FIXME? True value is 256/48 = 5.33333 ms */ - err = snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_TIME, - 5334, UINT_MAX); - if (err < 0) - return err; - err = snd_pcm_hw_rule_noresample(runtime, 48000); - if (err < 0) - return err; ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL); if (ypcm == NULL) @@ -916,8 +904,11 @@ static int snd_ymfpci_playback_open_1(struct snd_pcm_substream *substream) ypcm->chip = chip; ypcm->type = PLAYBACK_VOICE; ypcm->substream = substream; + runtime->hw = snd_ymfpci_playback; runtime->private_data = ypcm; runtime->private_free = snd_ymfpci_pcm_free_substream; + /* FIXME? True value is 256/48 = 5.33333 ms */ + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX); return 0; } @@ -1022,18 +1013,6 @@ static int snd_ymfpci_capture_open(struct snd_pcm_substream *substream, struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ymfpci_pcm *ypcm; - int err; - - runtime->hw = snd_ymfpci_capture; - /* FIXME? True value is 256/48 = 5.33333 ms */ - err = snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_TIME, - 5334, UINT_MAX); - if (err < 0) - return err; - err = snd_pcm_hw_rule_noresample(runtime, 48000); - if (err < 0) - return err; ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL); if (ypcm == NULL) @@ -1043,6 +1022,9 @@ static int snd_ymfpci_capture_open(struct snd_pcm_substream *substream, ypcm->substream = substream; ypcm->capture_bank_number = capture_bank_number; chip->capture_substream[capture_bank_number] = substream; + runtime->hw = snd_ymfpci_capture; + /* FIXME? True value is 256/48 = 5.33333 ms */ + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX); runtime->private_data = ypcm; runtime->private_free = snd_ymfpci_pcm_free_substream; snd_ymfpci_hw_start(chip); @@ -1633,7 +1615,7 @@ YMFPCI_DOUBLE("ADC Playback Volume", 0, YDSXGR_PRIADCOUTVOL), YMFPCI_DOUBLE("ADC Capture Volume", 0, YDSXGR_PRIADCLOOPVOL), YMFPCI_DOUBLE("ADC Playback Volume", 1, YDSXGR_SECADCOUTVOL), YMFPCI_DOUBLE("ADC Capture Volume", 1, YDSXGR_SECADCLOOPVOL), -YMFPCI_DOUBLE("FM Legacy Playback Volume", 0, YDSXGR_LEGACYOUTVOL), +YMFPCI_DOUBLE("FM Legacy Volume", 0, YDSXGR_LEGACYOUTVOL), YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ", PLAYBACK,VOLUME), 0, YDSXGR_ZVOUTVOL), YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("", CAPTURE,VOLUME), 0, YDSXGR_ZVLOOPVOL), YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ",PLAYBACK,VOLUME), 1, YDSXGR_SPDIFOUTVOL), diff --git a/trunk/sound/ppc/keywest.c b/trunk/sound/ppc/keywest.c index 4080becf4cef..8f064c7ce745 100644 --- a/trunk/sound/ppc/keywest.c +++ b/trunk/sound/ppc/keywest.c @@ -82,6 +82,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter) static int keywest_remove(struct i2c_client *client) { + i2c_set_clientdata(client, NULL); if (! keywest_ctx) return 0; if (client == keywest_ctx->client) diff --git a/trunk/sound/ppc/snd_ps3.c b/trunk/sound/ppc/snd_ps3.c index 775bd95d4be6..bc823a547550 100644 --- a/trunk/sound/ppc/snd_ps3.c +++ b/trunk/sound/ppc/snd_ps3.c @@ -845,7 +845,7 @@ static int __devinit snd_ps3_allocate_irq(void) return ret; } - ret = request_irq(the_card.irq_no, snd_ps3_interrupt, 0, + ret = request_irq(the_card.irq_no, snd_ps3_interrupt, IRQF_DISABLED, SND_PS3_DRIVER_NAME, &the_card); if (ret) { pr_info("%s: request_irq failed (%d)\n", __func__, ret); diff --git a/trunk/sound/soc/au1x/dma.c b/trunk/sound/soc/au1x/dma.c index 177f7137a9c8..7aa5b7606777 100644 --- a/trunk/sound/soc/au1x/dma.c +++ b/trunk/sound/soc/au1x/dma.c @@ -211,7 +211,7 @@ static int alchemy_pcm_open(struct snd_pcm_substream *substream) /* DMA setup */ name = (s == SNDRV_PCM_STREAM_PLAYBACK) ? "audio-tx" : "audio-rx"; ctx->stream[s].dma = request_au1000_dma(dmaids[s], name, - au1000_dma_interrupt, 0, + au1000_dma_interrupt, IRQF_DISABLED, &ctx->stream[s]); set_dma_mode(ctx->stream[s].dma, get_dma_mode(ctx->stream[s].dma) & ~DMA_NC); diff --git a/trunk/sound/soc/codecs/tlv320dac33.c b/trunk/sound/soc/codecs/tlv320dac33.c index dc8a2b2bdc1c..3f4920d5456d 100644 --- a/trunk/sound/soc/codecs/tlv320dac33.c +++ b/trunk/sound/soc/codecs/tlv320dac33.c @@ -1419,7 +1419,7 @@ static int dac33_soc_probe(struct snd_soc_codec *codec) /* Check if the IRQ number is valid and request it */ if (dac33->irq >= 0) { ret = request_irq(dac33->irq, dac33_interrupt_handler, - IRQF_TRIGGER_RISING, + IRQF_TRIGGER_RISING | IRQF_DISABLED, codec->name, codec); if (ret < 0) { dev_err(codec->dev, "Could not request IRQ%d (%d)\n", diff --git a/trunk/sound/soc/codecs/wm8940.c b/trunk/sound/soc/codecs/wm8940.c index dc5cb3150857..de9ec9b8b7d9 100644 --- a/trunk/sound/soc/codecs/wm8940.c +++ b/trunk/sound/soc/codecs/wm8940.c @@ -621,7 +621,7 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8940_BCLKDIV: - reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFEF3; + reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFE3; ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2)); break; case WM8940_MCLKDIV: diff --git a/trunk/sound/soc/nuc900/nuc900-pcm.c b/trunk/sound/soc/nuc900/nuc900-pcm.c index ae8d6806966b..4e3626b9d8f9 100644 --- a/trunk/sound/soc/nuc900/nuc900-pcm.c +++ b/trunk/sound/soc/nuc900/nuc900-pcm.c @@ -268,7 +268,7 @@ static int nuc900_dma_open(struct snd_pcm_substream *substream) nuc900_audio = nuc900_ac97_data; if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt, - 0, "nuc900-dma", substream)) + IRQF_DISABLED, "nuc900-dma", substream)) return -EBUSY; runtime->private_data = nuc900_audio; diff --git a/trunk/sound/soc/samsung/ac97.c b/trunk/sound/soc/samsung/ac97.c index b5e922f469d5..65ea53884806 100644 --- a/trunk/sound/soc/samsung/ac97.c +++ b/trunk/sound/soc/samsung/ac97.c @@ -444,7 +444,7 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev) } ret = request_irq(irq_res->start, s3c_ac97_irq, - 0, "AC97", NULL); + IRQF_DISABLED, "AC97", NULL); if (ret < 0) { dev_err(&pdev->dev, "ac97: interrupt request failed.\n"); goto err4; diff --git a/trunk/sound/soc/sh/fsi.c b/trunk/sound/soc/sh/fsi.c index a32fd16ad668..916b9f99b7e7 100644 --- a/trunk/sound/soc/sh/fsi.c +++ b/trunk/sound/soc/sh/fsi.c @@ -1285,7 +1285,7 @@ static int fsi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); dev_set_drvdata(&pdev->dev, master); - ret = request_irq(irq, &fsi_interrupt, 0, + ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, id_entry->name, master); if (ret) { dev_err(&pdev->dev, "irq request err\n"); diff --git a/trunk/sound/soc/txx9/txx9aclc-ac97.c b/trunk/sound/soc/txx9/txx9aclc-ac97.c index a4e3f5501847..743d07b82c06 100644 --- a/trunk/sound/soc/txx9/txx9aclc-ac97.c +++ b/trunk/sound/soc/txx9/txx9aclc-ac97.c @@ -201,7 +201,7 @@ static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev) if (!drvdata->base) return -EBUSY; err = devm_request_irq(&pdev->dev, irq, txx9aclc_ac97_irq, - 0, dev_name(&pdev->dev), drvdata); + IRQF_DISABLED, dev_name(&pdev->dev), drvdata); if (err < 0) return err; diff --git a/trunk/sound/sparc/amd7930.c b/trunk/sound/sparc/amd7930.c index f036776380b5..ad7d4d7d9237 100644 --- a/trunk/sound/sparc/amd7930.c +++ b/trunk/sound/sparc/amd7930.c @@ -962,7 +962,7 @@ static int __devinit snd_amd7930_create(struct snd_card *card, amd7930_idle(amd); if (request_irq(irq, snd_amd7930_interrupt, - IRQF_SHARED, "amd7930", amd)) { + IRQF_DISABLED | IRQF_SHARED, "amd7930", amd)) { snd_printk(KERN_ERR "amd7930-%d: Unable to grab IRQ %d\n", dev, irq); snd_amd7930_free(amd); diff --git a/trunk/sound/usb/6fire/firmware.c b/trunk/sound/usb/6fire/firmware.c index 07bcfe4d18a7..1e3ae3327dd3 100644 --- a/trunk/sound/usb/6fire/firmware.c +++ b/trunk/sound/usb/6fire/firmware.c @@ -16,7 +16,6 @@ #include #include -#include #include "firmware.h" #include "chip.h" @@ -60,19 +59,21 @@ struct ihex_record { unsigned int txt_offset; /* current position in txt_data */ }; -static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc) +static u8 usb6fire_fw_ihex_nibble(const u8 n) { - u8 val = 0; - int hval; - - hval = hex_to_bin(data[0]); - if (hval >= 0) - val |= (hval << 4); - - hval = hex_to_bin(data[1]); - if (hval >= 0) - val |= hval; + if (n >= '0' && n <= '9') + return n - '0'; + else if (n >= 'A' && n <= 'F') + return n - ('A' - 10); + else if (n >= 'a' && n <= 'f') + return n - ('a' - 10); + return 0; +} +static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc) +{ + u8 val = (usb6fire_fw_ihex_nibble(data[0]) << 4) | + usb6fire_fw_ihex_nibble(data[1]); *crc += val; return val; } diff --git a/trunk/sound/usb/Kconfig b/trunk/sound/usb/Kconfig index 3efc21c3d67c..8beb77563da2 100644 --- a/trunk/sound/usb/Kconfig +++ b/trunk/sound/usb/Kconfig @@ -67,7 +67,6 @@ config SND_USB_CAIAQ * Native Instruments Guitar Rig mobile * Native Instruments Traktor Kontrol X1 * Native Instruments Traktor Kontrol S4 - * Native Instruments Maschine Controller To compile this driver as a module, choose M here: the module will be called snd-usb-caiaq. @@ -86,7 +85,6 @@ config SND_USB_CAIAQ_INPUT * Native Instruments Kore Controller 2 * Native Instruments Audio Kontrol 1 * Native Instruments Traktor Kontrol S4 - * Native Instruments Maschine Controller config SND_USB_US122L tristate "Tascam US-122L USB driver" diff --git a/trunk/sound/usb/Makefile b/trunk/sound/usb/Makefile index ac256dc4c6be..cf9ed66445fa 100644 --- a/trunk/sound/usb/Makefile +++ b/trunk/sound/usb/Makefile @@ -3,16 +3,16 @@ # snd-usb-audio-objs := card.o \ - clock.o \ - endpoint.o \ - format.o \ - helper.o \ mixer.o \ mixer_quirks.o \ - pcm.o \ proc.o \ quirks.o \ - stream.o + format.o \ + endpoint.o \ + urb.o \ + pcm.o \ + helper.o \ + clock.o snd-usbmidi-lib-objs := midi.o diff --git a/trunk/sound/usb/caiaq/audio.c b/trunk/sound/usb/caiaq/audio.c index 2cf87f5afed4..d0d493ca28ae 100644 --- a/trunk/sound/usb/caiaq/audio.c +++ b/trunk/sound/usb/caiaq/audio.c @@ -139,12 +139,8 @@ static void stream_stop(struct snd_usb_caiaqdev *dev) for (i = 0; i < N_URBS; i++) { usb_kill_urb(dev->data_urbs_in[i]); - - if (test_bit(i, &dev->outurb_active_mask)) - usb_kill_urb(dev->data_urbs_out[i]); + usb_kill_urb(dev->data_urbs_out[i]); } - - dev->outurb_active_mask = 0; } static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream) @@ -616,9 +612,8 @@ static void read_completed(struct urb *urb) { struct snd_usb_caiaq_cb_info *info = urb->context; struct snd_usb_caiaqdev *dev; - struct urb *out = NULL; - int i, frame, len, send_it = 0, outframe = 0; - size_t offset = 0; + struct urb *out; + int frame, len, send_it = 0, outframe = 0; if (urb->status || !info) return; @@ -628,17 +623,7 @@ static void read_completed(struct urb *urb) if (!dev->streaming) return; - /* find an unused output urb that is unused */ - for (i = 0; i < N_URBS; i++) - if (test_and_set_bit(i, &dev->outurb_active_mask) == 0) { - out = dev->data_urbs_out[i]; - break; - } - - if (!out) { - log("Unable to find an output urb to use\n"); - goto requeue; - } + out = dev->data_urbs_out[info->index]; /* read the recently received packet and send back one which has * the same layout */ @@ -649,8 +634,7 @@ static void read_completed(struct urb *urb) len = urb->iso_frame_desc[outframe].actual_length; out->iso_frame_desc[outframe].length = len; out->iso_frame_desc[outframe].actual_length = 0; - out->iso_frame_desc[outframe].offset = offset; - offset += len; + out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame; if (len > 0) { spin_lock(&dev->spinlock); @@ -666,15 +650,11 @@ static void read_completed(struct urb *urb) } if (send_it) { - out->number_of_packets = outframe; + out->number_of_packets = FRAMES_PER_URB; out->transfer_flags = URB_ISO_ASAP; usb_submit_urb(out, GFP_ATOMIC); - } else { - struct snd_usb_caiaq_cb_info *oinfo = out->context; - clear_bit(oinfo->index, &dev->outurb_active_mask); } -requeue: /* re-submit inbound urb */ for (frame = 0; frame < FRAMES_PER_URB; frame++) { urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; @@ -696,8 +676,6 @@ static void write_completed(struct urb *urb) dev->output_running = 1; wake_up(&dev->prepare_wait_queue); } - - clear_bit(info->index, &dev->outurb_active_mask); } static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) @@ -849,9 +827,6 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) if (!dev->data_cb_info) return -ENOMEM; - dev->outurb_active_mask = 0; - BUILD_BUG_ON(N_URBS > (sizeof(dev->outurb_active_mask) * 8)); - for (i = 0; i < N_URBS; i++) { dev->data_cb_info[i].dev = dev; dev->data_cb_info[i].index = i; diff --git a/trunk/sound/usb/caiaq/device.c b/trunk/sound/usb/caiaq/device.c index 3eb605bd9503..45bc4a2dc6f0 100644 --- a/trunk/sound/usb/caiaq/device.c +++ b/trunk/sound/usb/caiaq/device.c @@ -50,8 +50,7 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, Session I/O}," "{Native Instruments, GuitarRig mobile}" "{Native Instruments, Traktor Kontrol X1}" - "{Native Instruments, Traktor Kontrol S4}" - "{Native Instruments, Maschine Controller}"); + "{Native Instruments, Traktor Kontrol S4}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ @@ -147,11 +146,6 @@ static struct usb_device_id snd_usb_id_table[] = { .idVendor = USB_VID_NATIVEINSTRUMENTS, .idProduct = USB_PID_TRAKTORAUDIO2 }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = USB_VID_NATIVEINSTRUMENTS, - .idProduct = USB_PID_MASCHINECONTROLLER - }, { /* terminator */ } }; diff --git a/trunk/sound/usb/caiaq/device.h b/trunk/sound/usb/caiaq/device.h index 562b0bff9c41..b2b310194ffa 100644 --- a/trunk/sound/usb/caiaq/device.h +++ b/trunk/sound/usb/caiaq/device.h @@ -18,7 +18,6 @@ #define USB_PID_TRAKTORKONTROLX1 0x2305 #define USB_PID_TRAKTORKONTROLS4 0xbaff #define USB_PID_TRAKTORAUDIO2 0x041d -#define USB_PID_MASCHINECONTROLLER 0x0808 #define EP1_BUFSIZE 64 #define EP4_BUFSIZE 512 @@ -97,7 +96,6 @@ struct snd_usb_caiaqdev { int input_panic, output_panic, warned; char *audio_in_buf, *audio_out_buf; unsigned int samplerates, bpp; - unsigned long outurb_active_mask; struct snd_pcm_substream *sub_playback[MAX_STREAMS]; struct snd_pcm_substream *sub_capture[MAX_STREAMS]; diff --git a/trunk/sound/usb/caiaq/input.c b/trunk/sound/usb/caiaq/input.c index 26a121b42c3c..4432ef7a70a9 100644 --- a/trunk/sound/usb/caiaq/input.c +++ b/trunk/sound/usb/caiaq/input.c @@ -30,7 +30,7 @@ static unsigned short keycode_ak1[] = { KEY_C, KEY_B, KEY_A }; static unsigned short keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7 }; static unsigned short keycode_rk3[] = { KEY_1, KEY_2, KEY_3, KEY_4, - KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 }; + KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 }; static unsigned short keycode_kore[] = { KEY_FN_F1, /* "menu" */ @@ -67,61 +67,6 @@ static unsigned short keycode_kore[] = { KEY_BRL_DOT5 }; -#define MASCHINE_BUTTONS (42) -#define MASCHINE_BUTTON(X) ((X) + BTN_MISC) -#define MASCHINE_PADS (16) -#define MASCHINE_PAD(X) ((X) + ABS_PRESSURE) - -static unsigned short keycode_maschine[] = { - MASCHINE_BUTTON(40), /* mute */ - MASCHINE_BUTTON(39), /* solo */ - MASCHINE_BUTTON(38), /* select */ - MASCHINE_BUTTON(37), /* duplicate */ - MASCHINE_BUTTON(36), /* navigate */ - MASCHINE_BUTTON(35), /* pad mode */ - MASCHINE_BUTTON(34), /* pattern */ - MASCHINE_BUTTON(33), /* scene */ - KEY_RESERVED, /* spacer */ - - MASCHINE_BUTTON(30), /* rec */ - MASCHINE_BUTTON(31), /* erase */ - MASCHINE_BUTTON(32), /* shift */ - MASCHINE_BUTTON(28), /* grid */ - MASCHINE_BUTTON(27), /* > */ - MASCHINE_BUTTON(26), /* < */ - MASCHINE_BUTTON(25), /* restart */ - - MASCHINE_BUTTON(21), /* E */ - MASCHINE_BUTTON(22), /* F */ - MASCHINE_BUTTON(23), /* G */ - MASCHINE_BUTTON(24), /* H */ - MASCHINE_BUTTON(20), /* D */ - MASCHINE_BUTTON(19), /* C */ - MASCHINE_BUTTON(18), /* B */ - MASCHINE_BUTTON(17), /* A */ - - MASCHINE_BUTTON(0), /* control */ - MASCHINE_BUTTON(2), /* browse */ - MASCHINE_BUTTON(4), /* < */ - MASCHINE_BUTTON(6), /* snap */ - MASCHINE_BUTTON(7), /* autowrite */ - MASCHINE_BUTTON(5), /* > */ - MASCHINE_BUTTON(3), /* sampling */ - MASCHINE_BUTTON(1), /* step */ - - MASCHINE_BUTTON(15), /* 8 softkeys */ - MASCHINE_BUTTON(14), - MASCHINE_BUTTON(13), - MASCHINE_BUTTON(12), - MASCHINE_BUTTON(11), - MASCHINE_BUTTON(10), - MASCHINE_BUTTON(9), - MASCHINE_BUTTON(8), - - MASCHINE_BUTTON(16), /* note repeat */ - MASCHINE_BUTTON(29) /* play */ -}; - #define KONTROLX1_INPUTS (40) #define KONTROLS4_BUTTONS (12 * 8) #define KONTROLS4_AXIS (46) @@ -273,29 +218,6 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, input_report_abs(input_dev, ABS_HAT3Y, i); input_sync(input_dev); break; - - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): - /* 4 under the left screen */ - input_report_abs(input_dev, ABS_HAT0X, decode_erp(buf[21], buf[20])); - input_report_abs(input_dev, ABS_HAT0Y, decode_erp(buf[15], buf[14])); - input_report_abs(input_dev, ABS_HAT1X, decode_erp(buf[9], buf[8])); - input_report_abs(input_dev, ABS_HAT1Y, decode_erp(buf[3], buf[2])); - - /* 4 under the right screen */ - input_report_abs(input_dev, ABS_HAT2X, decode_erp(buf[19], buf[18])); - input_report_abs(input_dev, ABS_HAT2Y, decode_erp(buf[13], buf[12])); - input_report_abs(input_dev, ABS_HAT3X, decode_erp(buf[7], buf[6])); - input_report_abs(input_dev, ABS_HAT3Y, decode_erp(buf[1], buf[0])); - - /* volume */ - input_report_abs(input_dev, ABS_RX, decode_erp(buf[17], buf[16])); - /* tempo */ - input_report_abs(input_dev, ABS_RY, decode_erp(buf[11], buf[10])); - /* swing */ - input_report_abs(input_dev, ABS_RZ, decode_erp(buf[5], buf[4])); - - input_sync(input_dev); - break; } } @@ -478,25 +400,6 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev, input_sync(dev->input_dev); } -#define MASCHINE_MSGBLOCK_SIZE 2 - -static void snd_usb_caiaq_maschine_dispatch(struct snd_usb_caiaqdev *dev, - const unsigned char *buf, - unsigned int len) -{ - unsigned int i, pad_id; - uint16_t pressure; - - for (i = 0; i < MASCHINE_PADS; i++) { - pressure = be16_to_cpu(buf[i * 2] << 8 | buf[(i * 2) + 1]); - pad_id = pressure >> 12; - - input_report_abs(dev->input_dev, MASCHINE_PAD(pad_id), pressure & 0xfff); - } - - input_sync(dev->input_dev); -} - static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) { struct snd_usb_caiaqdev *dev = urb->context; @@ -522,13 +425,6 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length); break; - - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): - if (urb->actual_length < (MASCHINE_PADS * MASCHINE_MSGBLOCK_SIZE)) - goto requeue; - - snd_usb_caiaq_maschine_dispatch(dev, buf, urb->actual_length); - break; } requeue: @@ -548,7 +444,6 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev) switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) return -EIO; break; @@ -567,7 +462,6 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev) switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): usb_kill_urb(dev->ep4_in_urb); break; } @@ -758,50 +652,6 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) break; - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): - input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) | - BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) | - BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) | - BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) | - BIT_MASK(ABS_RX) | BIT_MASK(ABS_RY) | - BIT_MASK(ABS_RZ); - - BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_maschine)); - memcpy(dev->keycode, keycode_maschine, sizeof(keycode_maschine)); - input->keycodemax = ARRAY_SIZE(keycode_maschine); - - for (i = 0; i < MASCHINE_PADS; i++) { - input->absbit[0] |= MASCHINE_PAD(i); - input_set_abs_params(input, MASCHINE_PAD(i), 0, 0xfff, 5, 10); - } - - input_set_abs_params(input, ABS_HAT0X, 0, 999, 0, 10); - input_set_abs_params(input, ABS_HAT0Y, 0, 999, 0, 10); - input_set_abs_params(input, ABS_HAT1X, 0, 999, 0, 10); - input_set_abs_params(input, ABS_HAT1Y, 0, 999, 0, 10); - input_set_abs_params(input, ABS_HAT2X, 0, 999, 0, 10); - input_set_abs_params(input, ABS_HAT2Y, 0, 999, 0, 10); - input_set_abs_params(input, ABS_HAT3X, 0, 999, 0, 10); - input_set_abs_params(input, ABS_HAT3Y, 0, 999, 0, 10); - input_set_abs_params(input, ABS_RX, 0, 999, 0, 10); - input_set_abs_params(input, ABS_RY, 0, 999, 0, 10); - input_set_abs_params(input, ABS_RZ, 0, 999, 0, 10); - - dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->ep4_in_urb) { - ret = -ENOMEM; - goto exit_free_idev; - } - - usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev, - usb_rcvbulkpipe(usb_dev, 0x4), - dev->ep4_in_buf, EP4_BUFSIZE, - snd_usb_caiaq_ep4_reply_dispatch, dev); - - snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); - break; - default: /* no input methods supported on this device */ goto exit_free_idev; @@ -814,17 +664,15 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) for (i = 0; i < input->keycodemax; i++) __set_bit(dev->keycode[i], input->keybit); - dev->input_dev = input; - ret = input_register_device(input); if (ret < 0) goto exit_free_idev; + dev->input_dev = input; return 0; exit_free_idev: input_free_device(input); - dev->input_dev = NULL; return ret; } @@ -840,3 +688,4 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) input_unregister_device(dev->input_dev); dev->input_dev = NULL; } + diff --git a/trunk/sound/usb/card.c b/trunk/sound/usb/card.c index c1575eafff12..781d9e61adfb 100644 --- a/trunk/sound/usb/card.c +++ b/trunk/sound/usb/card.c @@ -65,9 +65,9 @@ #include "helper.h" #include "debug.h" #include "pcm.h" +#include "urb.h" #include "format.h" #include "power.h" -#include "stream.h" MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("USB Audio"); @@ -185,7 +185,7 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int return -EINVAL; } - if (! snd_usb_parse_audio_interface(chip, interface)) { + if (! snd_usb_parse_audio_endpoints(chip, interface)) { usb_set_interface(dev, interface, 0); /* reset the current interface */ usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); return -EINVAL; @@ -530,11 +530,8 @@ snd_usb_audio_probe(struct usb_device *dev, return chip; __error: - if (chip) { - if (!chip->num_interfaces) - snd_card_free(chip->card); - chip->probing = 0; - } + if (chip && !chip->num_interfaces) + snd_card_free(chip->card); mutex_unlock(®ister_mutex); __err_val: return NULL; diff --git a/trunk/sound/usb/card.h b/trunk/sound/usb/card.h index a39edcc32a93..ae4251d5abf7 100644 --- a/trunk/sound/usb/card.h +++ b/trunk/sound/usb/card.h @@ -94,8 +94,6 @@ struct snd_usb_substream { spinlock_t lock; struct snd_urb_ops ops; /* callbacks (must be filled at init) */ - int last_frame_number; /* stored frame number */ - int last_delay; /* stored delay */ }; struct snd_usb_stream { diff --git a/trunk/sound/usb/clock.c b/trunk/sound/usb/clock.c index 379baad3d5ad..075195e8661a 100644 --- a/trunk/sound/usb/clock.c +++ b/trunk/sound/usb/clock.c @@ -91,7 +91,7 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, UAC2_CX_CLOCK_SELECTOR << 8, snd_usb_ctrl_intf(chip) | (selector_id << 8), - &buf, sizeof(buf)); + &buf, sizeof(buf), 1000); if (ret < 0) return ret; @@ -118,7 +118,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, UAC2_CS_CONTROL_CLOCK_VALID << 8, snd_usb_ctrl_intf(chip) | (source_id << 8), - &data, sizeof(data)); + &data, sizeof(data), 1000); if (err < 0) { snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", @@ -222,7 +222,7 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, - data, sizeof(data))) < 0) { + data, sizeof(data), 1000)) < 0) { snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", dev->devnum, iface, fmt->altsetting, rate, ep); return err; @@ -231,7 +231,7 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, - data, sizeof(data))) < 0) { + data, sizeof(data), 1000)) < 0) { snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", dev->devnum, iface, fmt->altsetting, ep); return 0; /* some devices don't support reading */ @@ -273,7 +273,7 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, UAC2_CS_CONTROL_SAM_FREQ << 8, snd_usb_ctrl_intf(chip) | (clock << 8), - data, sizeof(data))) < 0) { + data, sizeof(data), 1000)) < 0) { snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", dev->devnum, iface, fmt->altsetting, rate); return err; @@ -283,7 +283,7 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, UAC2_CS_CONTROL_SAM_FREQ << 8, snd_usb_ctrl_intf(chip) | (clock << 8), - data, sizeof(data))) < 0) { + data, sizeof(data), 1000)) < 0) { snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", dev->devnum, iface, fmt->altsetting); return err; diff --git a/trunk/sound/usb/endpoint.c b/trunk/sound/usb/endpoint.c index 81c6edecd862..7c0d21ecd821 100644 --- a/trunk/sound/usb/endpoint.c +++ b/trunk/sound/usb/endpoint.c @@ -15,951 +15,436 @@ * */ -#include #include +#include #include #include +#include #include #include #include "usbaudio.h" -#include "helper.h" #include "card.h" +#include "proc.h" +#include "quirks.h" #include "endpoint.h" +#include "urb.h" #include "pcm.h" +#include "helper.h" +#include "format.h" +#include "clock.h" /* - * convert a sampling rate into our full speed format (fs/1000 in Q16.16) - * this will overflow at approx 524 kHz - */ -static inline unsigned get_usb_full_speed_rate(unsigned int rate) -{ - return ((rate << 13) + 62) / 125; -} - -/* - * convert a sampling rate into USB high speed format (fs/8000 in Q16.16) - * this will overflow at approx 4 MHz - */ -static inline unsigned get_usb_high_speed_rate(unsigned int rate) -{ - return ((rate << 10) + 62) / 125; -} - -/* - * unlink active urbs. - */ -static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep) -{ - struct snd_usb_audio *chip = subs->stream->chip; - unsigned int i; - int async; - - subs->running = 0; - - if (!force && subs->stream->chip->shutdown) /* to be sure... */ - return -EBADFD; - - async = !can_sleep && chip->async_unlink; - - if (!async && in_interrupt()) - return 0; - - for (i = 0; i < subs->nurbs; i++) { - if (test_bit(i, &subs->active_mask)) { - if (!test_and_set_bit(i, &subs->unlink_mask)) { - struct urb *u = subs->dataurb[i].urb; - if (async) - usb_unlink_urb(u); - else - usb_kill_urb(u); - } - } - } - if (subs->syncpipe) { - for (i = 0; i < SYNC_URBS; i++) { - if (test_bit(i+16, &subs->active_mask)) { - if (!test_and_set_bit(i+16, &subs->unlink_mask)) { - struct urb *u = subs->syncurb[i].urb; - if (async) - usb_unlink_urb(u); - else - usb_kill_urb(u); - } - } - } - } - return 0; -} - - -/* - * release a urb data + * free a substream */ -static void release_urb_ctx(struct snd_urb_ctx *u) +static void free_substream(struct snd_usb_substream *subs) { - if (u->urb) { - if (u->buffer_size) - usb_free_coherent(u->subs->dev, u->buffer_size, - u->urb->transfer_buffer, - u->urb->transfer_dma); - usb_free_urb(u->urb); - u->urb = NULL; + struct list_head *p, *n; + + if (!subs->num_formats) + return; /* not initialized */ + list_for_each_safe(p, n, &subs->fmt_list) { + struct audioformat *fp = list_entry(p, struct audioformat, list); + kfree(fp->rate_table); + kfree(fp); } + kfree(subs->rate_list.list); } -/* - * wait until all urbs are processed. - */ -static int wait_clear_urbs(struct snd_usb_substream *subs) -{ - unsigned long end_time = jiffies + msecs_to_jiffies(1000); - unsigned int i; - int alive; - - do { - alive = 0; - for (i = 0; i < subs->nurbs; i++) { - if (test_bit(i, &subs->active_mask)) - alive++; - } - if (subs->syncpipe) { - for (i = 0; i < SYNC_URBS; i++) { - if (test_bit(i + 16, &subs->active_mask)) - alive++; - } - } - if (! alive) - break; - schedule_timeout_uninterruptible(1); - } while (time_before(jiffies, end_time)); - if (alive) - snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); - return 0; -} - -/* - * release a substream - */ -void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force) -{ - int i; - - /* stop urbs (to be sure) */ - deactivate_urbs(subs, force, 1); - wait_clear_urbs(subs); - - for (i = 0; i < MAX_URBS; i++) - release_urb_ctx(&subs->dataurb[i]); - for (i = 0; i < SYNC_URBS; i++) - release_urb_ctx(&subs->syncurb[i]); - usb_free_coherent(subs->dev, SYNC_URBS * 4, - subs->syncbuf, subs->sync_dma); - subs->syncbuf = NULL; - subs->nurbs = 0; -} /* - * complete callback from data urb + * free a usb stream instance */ -static void snd_complete_urb(struct urb *urb) +static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) { - struct snd_urb_ctx *ctx = urb->context; - struct snd_usb_substream *subs = ctx->subs; - struct snd_pcm_substream *substream = ctx->subs->pcm_substream; - int err = 0; - - if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) || - !subs->running || /* can be stopped during retire callback */ - (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || - (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - clear_bit(ctx->index, &subs->active_mask); - if (err < 0) { - snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - } - } + free_substream(&stream->substream[0]); + free_substream(&stream->substream[1]); + list_del(&stream->list); + kfree(stream); } - -/* - * complete callback from sync urb - */ -static void snd_complete_sync_urb(struct urb *urb) +static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) { - struct snd_urb_ctx *ctx = urb->context; - struct snd_usb_substream *subs = ctx->subs; - struct snd_pcm_substream *substream = ctx->subs->pcm_substream; - int err = 0; - - if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) || - !subs->running || /* can be stopped during retire callback */ - (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || - (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - clear_bit(ctx->index + 16, &subs->active_mask); - if (err < 0) { - snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - } + struct snd_usb_stream *stream = pcm->private_data; + if (stream) { + stream->pcm = NULL; + snd_usb_audio_stream_free(stream); } } /* - * initialize a substream for plaback/capture + * add this endpoint to the chip instance. + * if a stream with the same endpoint already exists, append to it. + * if not, create a new pcm stream. */ -int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, - unsigned int period_bytes, - unsigned int rate, - unsigned int frame_bits) +int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp) { - unsigned int maxsize, i; - int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; - unsigned int urb_packs, total_packs, packs_per_ms; - struct snd_usb_audio *chip = subs->stream->chip; - - /* calculate the frequency in 16.16 format */ - if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) - subs->freqn = get_usb_full_speed_rate(rate); - else - subs->freqn = get_usb_high_speed_rate(rate); - subs->freqm = subs->freqn; - subs->freqshift = INT_MIN; - /* calculate max. frequency */ - if (subs->maxpacksize) { - /* whatever fits into a max. size packet */ - maxsize = subs->maxpacksize; - subs->freqmax = (maxsize / (frame_bits >> 3)) - << (16 - subs->datainterval); - } else { - /* no max. packet size: just take 25% higher than nominal */ - subs->freqmax = subs->freqn + (subs->freqn >> 2); - maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) - >> (16 - subs->datainterval); - } - subs->phase = 0; - - if (subs->fill_max) - subs->curpacksize = subs->maxpacksize; - else - subs->curpacksize = maxsize; + struct list_head *p; + struct snd_usb_stream *as; + struct snd_usb_substream *subs; + struct snd_pcm *pcm; + int err; - if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) - packs_per_ms = 8 >> subs->datainterval; - else - packs_per_ms = 1; - - if (is_playback) { - urb_packs = max(chip->nrpacks, 1); - urb_packs = min(urb_packs, (unsigned int)MAX_PACKS); - } else - urb_packs = 1; - urb_packs *= packs_per_ms; - if (subs->syncpipe) - urb_packs = min(urb_packs, 1U << subs->syncinterval); - - /* decide how many packets to be used */ - if (is_playback) { - unsigned int minsize, maxpacks; - /* determine how small a packet can be */ - minsize = (subs->freqn >> (16 - subs->datainterval)) - * (frame_bits >> 3); - /* with sync from device, assume it can be 12% lower */ - if (subs->syncpipe) - minsize -= minsize >> 3; - minsize = max(minsize, 1u); - total_packs = (period_bytes + minsize - 1) / minsize; - /* we need at least two URBs for queueing */ - if (total_packs < 2) { - total_packs = 2; - } else { - /* and we don't want too long a queue either */ - maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2); - total_packs = min(total_packs, maxpacks); + list_for_each(p, &chip->pcm_list) { + as = list_entry(p, struct snd_usb_stream, list); + if (as->fmt_type != fp->fmt_type) + continue; + subs = &as->substream[stream]; + if (!subs->endpoint) + continue; + if (subs->endpoint == fp->endpoint) { + list_add_tail(&fp->list, &subs->fmt_list); + subs->num_formats++; + subs->formats |= fp->formats; + return 0; } - } else { - while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) - urb_packs >>= 1; - total_packs = MAX_URBS * urb_packs; } - subs->nurbs = (total_packs + urb_packs - 1) / urb_packs; - if (subs->nurbs > MAX_URBS) { - /* too much... */ - subs->nurbs = MAX_URBS; - total_packs = MAX_URBS * urb_packs; - } else if (subs->nurbs < 2) { - /* too little - we need at least two packets - * to ensure contiguous playback/capture - */ - subs->nurbs = 2; - } - - /* allocate and initialize data urbs */ - for (i = 0; i < subs->nurbs; i++) { - struct snd_urb_ctx *u = &subs->dataurb[i]; - u->index = i; - u->subs = subs; - u->packets = (i + 1) * total_packs / subs->nurbs - - i * total_packs / subs->nurbs; - u->buffer_size = maxsize * u->packets; - if (subs->fmt_type == UAC_FORMAT_TYPE_II) - u->packets++; /* for transfer delimiter */ - u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); - if (!u->urb) - goto out_of_memory; - u->urb->transfer_buffer = - usb_alloc_coherent(subs->dev, u->buffer_size, - GFP_KERNEL, &u->urb->transfer_dma); - if (!u->urb->transfer_buffer) - goto out_of_memory; - u->urb->pipe = subs->datapipe; - u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - u->urb->interval = 1 << subs->datainterval; - u->urb->context = u; - u->urb->complete = snd_complete_urb; + /* look for an empty stream */ + list_for_each(p, &chip->pcm_list) { + as = list_entry(p, struct snd_usb_stream, list); + if (as->fmt_type != fp->fmt_type) + continue; + subs = &as->substream[stream]; + if (subs->endpoint) + continue; + err = snd_pcm_new_stream(as->pcm, stream, 1); + if (err < 0) + return err; + snd_usb_init_substream(as, stream, fp); + return 0; } - if (subs->syncpipe) { - /* allocate and initialize sync urbs */ - subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4, - GFP_KERNEL, &subs->sync_dma); - if (!subs->syncbuf) - goto out_of_memory; - for (i = 0; i < SYNC_URBS; i++) { - struct snd_urb_ctx *u = &subs->syncurb[i]; - u->index = i; - u->subs = subs; - u->packets = 1; - u->urb = usb_alloc_urb(1, GFP_KERNEL); - if (!u->urb) - goto out_of_memory; - u->urb->transfer_buffer = subs->syncbuf + i * 4; - u->urb->transfer_dma = subs->sync_dma + i * 4; - u->urb->transfer_buffer_length = 4; - u->urb->pipe = subs->syncpipe; - u->urb->transfer_flags = URB_ISO_ASAP | - URB_NO_TRANSFER_DMA_MAP; - u->urb->number_of_packets = 1; - u->urb->interval = 1 << subs->syncinterval; - u->urb->context = u; - u->urb->complete = snd_complete_sync_urb; - } + /* create a new pcm */ + as = kzalloc(sizeof(*as), GFP_KERNEL); + if (!as) + return -ENOMEM; + as->pcm_index = chip->pcm_devs; + as->chip = chip; + as->fmt_type = fp->fmt_type; + err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs, + stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0, + stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1, + &pcm); + if (err < 0) { + kfree(as); + return err; } - return 0; - -out_of_memory: - snd_usb_release_substream_urbs(subs, 0); - return -ENOMEM; -} + as->pcm = pcm; + pcm->private_data = as; + pcm->private_free = snd_usb_audio_pcm_free; + pcm->info_flags = 0; + if (chip->pcm_devs > 0) + sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); + else + strcpy(pcm->name, "USB Audio"); -/* - * prepare urb for full speed capture sync pipe - * - * fill the length and offset of each urb descriptor. - * the fixed 10.14 frequency is passed through the pipe. - */ -static int prepare_capture_sync_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) -{ - unsigned char *cp = urb->transfer_buffer; - struct snd_urb_ctx *ctx = urb->context; - - urb->dev = ctx->subs->dev; /* we need to set this at each time */ - urb->iso_frame_desc[0].length = 3; - urb->iso_frame_desc[0].offset = 0; - cp[0] = subs->freqn >> 2; - cp[1] = subs->freqn >> 10; - cp[2] = subs->freqn >> 18; - return 0; -} + snd_usb_init_substream(as, stream, fp); -/* - * prepare urb for high speed capture sync pipe - * - * fill the length and offset of each urb descriptor. - * the fixed 12.13 frequency is passed as 16.16 through the pipe. - */ -static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) -{ - unsigned char *cp = urb->transfer_buffer; - struct snd_urb_ctx *ctx = urb->context; - - urb->dev = ctx->subs->dev; /* we need to set this at each time */ - urb->iso_frame_desc[0].length = 4; - urb->iso_frame_desc[0].offset = 0; - cp[0] = subs->freqn; - cp[1] = subs->freqn >> 8; - cp[2] = subs->freqn >> 16; - cp[3] = subs->freqn >> 24; - return 0; -} + list_add(&as->list, &chip->pcm_list); + chip->pcm_devs++; -/* - * process after capture sync complete - * - nothing to do - */ -static int retire_capture_sync_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) -{ - return 0; -} + snd_usb_proc_pcm_format_add(as); -/* - * prepare urb for capture data pipe - * - * fill the offset and length of each descriptor. - * - * we use a temporary buffer to write the captured data. - * since the length of written data is determined by host, we cannot - * write onto the pcm buffer directly... the data is thus copied - * later at complete callback to the global buffer. - */ -static int prepare_capture_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) -{ - int i, offs; - struct snd_urb_ctx *ctx = urb->context; - - offs = 0; - urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = 0; i < ctx->packets; i++) { - urb->iso_frame_desc[i].offset = offs; - urb->iso_frame_desc[i].length = subs->curpacksize; - offs += subs->curpacksize; - } - urb->transfer_buffer_length = offs; - urb->number_of_packets = ctx->packets; return 0; } -/* - * process after capture complete - * - * copy the data from each desctiptor to the pcm buffer, and - * update the current position. - */ -static int retire_capture_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) +static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, + struct usb_host_interface *alts, + int protocol, int iface_no) { - unsigned long flags; - unsigned char *cp; - int i; - unsigned int stride, frames, bytes, oldptr; - int period_elapsed = 0; - - stride = runtime->frame_bits >> 3; - - for (i = 0; i < urb->number_of_packets; i++) { - cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; - if (urb->iso_frame_desc[i].status) { - snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); - // continue; - } - bytes = urb->iso_frame_desc[i].actual_length; - frames = bytes / stride; - if (!subs->txfr_quirk) - bytes = frames * stride; - if (bytes % (runtime->sample_bits >> 3) != 0) { -#ifdef CONFIG_SND_DEBUG_VERBOSE - int oldbytes = bytes; -#endif - bytes = frames * stride; - snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", - oldbytes, bytes); - } - /* update the current pointer */ - spin_lock_irqsave(&subs->lock, flags); - oldptr = subs->hwptr_done; - subs->hwptr_done += bytes; - if (subs->hwptr_done >= runtime->buffer_size * stride) - subs->hwptr_done -= runtime->buffer_size * stride; - frames = (bytes + (oldptr % stride)) / stride; - subs->transfer_done += frames; - if (subs->transfer_done >= runtime->period_size) { - subs->transfer_done -= runtime->period_size; - period_elapsed = 1; - } - spin_unlock_irqrestore(&subs->lock, flags); - /* copy a data chunk */ - if (oldptr + bytes > runtime->buffer_size * stride) { - unsigned int bytes1 = - runtime->buffer_size * stride - oldptr; - memcpy(runtime->dma_area + oldptr, cp, bytes1); - memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); - } else { - memcpy(runtime->dma_area + oldptr, cp, bytes); - } + /* parsed with a v1 header here. that's ok as we only look at the + * header first which is the same for both versions */ + struct uac_iso_endpoint_descriptor *csep; + struct usb_interface_descriptor *altsd = get_iface_desc(alts); + int attributes = 0; + + csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT); + + /* Creamware Noah has this descriptor after the 2nd endpoint */ + if (!csep && altsd->bNumEndpoints >= 2) + csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); + + if (!csep || csep->bLength < 7 || + csep->bDescriptorSubtype != UAC_EP_GENERAL) { + snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" + " class specific endpoint descriptor\n", + chip->dev->devnum, iface_no, + altsd->bAlternateSetting); + return 0; } - if (period_elapsed) - snd_pcm_period_elapsed(subs->pcm_substream); - return 0; -} -/* - * Process after capture complete when paused. Nothing to do. - */ -static int retire_paused_capture_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) -{ - return 0; -} + if (protocol == UAC_VERSION_1) { + attributes = csep->bmAttributes; + } else { + struct uac2_iso_endpoint_descriptor *csep2 = + (struct uac2_iso_endpoint_descriptor *) csep; + attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX; -/* - * prepare urb for playback sync pipe - * - * set up the offset and length to receive the current frequency. - */ -static int prepare_playback_sync_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) -{ - struct snd_urb_ctx *ctx = urb->context; + /* emulate the endpoint attributes of a v1 device */ + if (csep2->bmControls & UAC2_CONTROL_PITCH) + attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL; + } - urb->dev = ctx->subs->dev; /* we need to set this at each time */ - urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize); - urb->iso_frame_desc[0].offset = 0; - return 0; + return attributes; } -/* - * process after playback sync complete - * - * Full speed devices report feedback values in 10.14 format as samples per - * frame, high speed devices in 16.16 format as samples per microframe. - * Because the Audio Class 1 spec was written before USB 2.0, many high speed - * devices use a wrong interpretation, some others use an entirely different - * format. Therefore, we cannot predict what format any particular device uses - * and must detect it automatically. - */ -static int retire_playback_sync_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) +static struct uac2_input_terminal_descriptor * + snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, + int terminal_id) { - unsigned int f; - int shift; - unsigned long flags; - - if (urb->iso_frame_desc[0].status != 0 || - urb->iso_frame_desc[0].actual_length < 3) - return 0; - - f = le32_to_cpup(urb->transfer_buffer); - if (urb->iso_frame_desc[0].actual_length == 3) - f &= 0x00ffffff; - else - f &= 0x0fffffff; - if (f == 0) - return 0; - - if (unlikely(subs->freqshift == INT_MIN)) { - /* - * The first time we see a feedback value, determine its format - * by shifting it left or right until it matches the nominal - * frequency value. This assumes that the feedback does not - * differ from the nominal value more than +50% or -25%. - */ - shift = 0; - while (f < subs->freqn - subs->freqn / 4) { - f <<= 1; - shift++; - } - while (f > subs->freqn + subs->freqn / 2) { - f >>= 1; - shift--; - } - subs->freqshift = shift; - } - else if (subs->freqshift >= 0) - f <<= subs->freqshift; - else - f >>= -subs->freqshift; + struct uac2_input_terminal_descriptor *term = NULL; - if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) { - /* - * If the frequency looks valid, set it. - * This value is referred to in prepare_playback_urb(). - */ - spin_lock_irqsave(&subs->lock, flags); - subs->freqm = f; - spin_unlock_irqrestore(&subs->lock, flags); - } else { - /* - * Out of range; maybe the shift value is wrong. - * Reset it so that we autodetect again the next time. - */ - subs->freqshift = INT_MIN; + while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + term, UAC_INPUT_TERMINAL))) { + if (term->bTerminalID == terminal_id) + return term; } - return 0; + return NULL; } -/* determine the number of frames in the next packet */ -static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) +static struct uac2_output_terminal_descriptor * + snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, + int terminal_id) { - if (subs->fill_max) - return subs->maxframesize; - else { - subs->phase = (subs->phase & 0xffff) - + (subs->freqm << subs->datainterval); - return min(subs->phase >> 16, subs->maxframesize); - } -} + struct uac2_output_terminal_descriptor *term = NULL; -/* - * Prepare urb for streaming before playback starts or when paused. - * - * We don't have any data, so we send silence. - */ -static int prepare_nodata_playback_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) -{ - unsigned int i, offs, counts; - struct snd_urb_ctx *ctx = urb->context; - int stride = runtime->frame_bits >> 3; - - offs = 0; - urb->dev = ctx->subs->dev; - for (i = 0; i < ctx->packets; ++i) { - counts = snd_usb_audio_next_packet_size(subs); - urb->iso_frame_desc[i].offset = offs * stride; - urb->iso_frame_desc[i].length = counts * stride; - offs += counts; + while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + term, UAC_OUTPUT_TERMINAL))) { + if (term->bTerminalID == terminal_id) + return term; } - urb->number_of_packets = ctx->packets; - urb->transfer_buffer_length = offs * stride; - memset(urb->transfer_buffer, - runtime->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0, - offs * stride); - return 0; -} -/* - * prepare urb for playback data pipe - * - * Since a URB can handle only a single linear buffer, we must use double - * buffering when the data to be transferred overflows the buffer boundary. - * To avoid inconsistencies when updating hwptr_done, we use double buffering - * for all URBs. - */ -static int prepare_playback_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) -{ - int i, stride; - unsigned int counts, frames, bytes; - unsigned long flags; - int period_elapsed = 0; - struct snd_urb_ctx *ctx = urb->context; - - stride = runtime->frame_bits >> 3; - - frames = 0; - urb->dev = ctx->subs->dev; /* we need to set this at each time */ - urb->number_of_packets = 0; - spin_lock_irqsave(&subs->lock, flags); - for (i = 0; i < ctx->packets; i++) { - counts = snd_usb_audio_next_packet_size(subs); - /* set up descriptor */ - urb->iso_frame_desc[i].offset = frames * stride; - urb->iso_frame_desc[i].length = counts * stride; - frames += counts; - urb->number_of_packets++; - subs->transfer_done += counts; - if (subs->transfer_done >= runtime->period_size) { - subs->transfer_done -= runtime->period_size; - period_elapsed = 1; - if (subs->fmt_type == UAC_FORMAT_TYPE_II) { - if (subs->transfer_done > 0) { - /* FIXME: fill-max mode is not - * supported yet */ - frames -= subs->transfer_done; - counts -= subs->transfer_done; - urb->iso_frame_desc[i].length = - counts * stride; - subs->transfer_done = 0; - } - i++; - if (i < ctx->packets) { - /* add a transfer delimiter */ - urb->iso_frame_desc[i].offset = - frames * stride; - urb->iso_frame_desc[i].length = 0; - urb->number_of_packets++; - } - break; - } - } - if (period_elapsed) /* finish at the period boundary */ - break; - } - bytes = frames * stride; - if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { - /* err, the transferred area goes over buffer boundary. */ - unsigned int bytes1 = - runtime->buffer_size * stride - subs->hwptr_done; - memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done, bytes1); - memcpy(urb->transfer_buffer + bytes1, - runtime->dma_area, bytes - bytes1); - } else { - memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done, bytes); - } - subs->hwptr_done += bytes; - if (subs->hwptr_done >= runtime->buffer_size * stride) - subs->hwptr_done -= runtime->buffer_size * stride; - - /* update delay with exact number of samples queued */ - runtime->delay = subs->last_delay; - runtime->delay += frames; - subs->last_delay = runtime->delay; - - /* realign last_frame_number */ - subs->last_frame_number = usb_get_current_frame_number(subs->dev); - subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ - - spin_unlock_irqrestore(&subs->lock, flags); - urb->transfer_buffer_length = bytes; - if (period_elapsed) - snd_pcm_period_elapsed(subs->pcm_substream); - return 0; + return NULL; } -/* - * process after playback data complete - * - decrease the delay count again - */ -static int retire_playback_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) +int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) { - unsigned long flags; - int stride = runtime->frame_bits >> 3; - int processed = urb->transfer_buffer_length / stride; - int est_delay; + struct usb_device *dev; + struct usb_interface *iface; + struct usb_host_interface *alts; + struct usb_interface_descriptor *altsd; + int i, altno, err, stream; + int format = 0, num_channels = 0; + struct audioformat *fp = NULL; + int num, protocol, clock = 0; + struct uac_format_type_i_continuous_descriptor *fmt; - spin_lock_irqsave(&subs->lock, flags); + dev = chip->dev; - est_delay = snd_usb_pcm_delay(subs, runtime->rate); - /* update delay with exact number of samples played */ - if (processed > subs->last_delay) - subs->last_delay = 0; - else - subs->last_delay -= processed; - runtime->delay = subs->last_delay; + /* parse the interface's altsettings */ + iface = usb_ifnum_to_if(dev, iface_no); + + num = iface->num_altsetting; /* - * Report when delay estimate is off by more than 2ms. - * The error should be lower than 2ms since the estimate relies - * on two reads of a counter updated every ms. + * Dallas DS4201 workaround: It presents 5 altsettings, but the last + * one misses syncpipe, and does not produce any sound. */ - if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2) - snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n", - est_delay, subs->last_delay); - - spin_unlock_irqrestore(&subs->lock, flags); - return 0; -} + if (chip->usb_id == USB_ID(0x04fa, 0x4201)) + num = 4; + + for (i = 0; i < num; i++) { + alts = &iface->altsetting[i]; + altsd = get_iface_desc(alts); + protocol = altsd->bInterfaceProtocol; + /* skip invalid one */ + if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && + altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || + (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING && + altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || + altsd->bNumEndpoints < 1 || + le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) + continue; + /* must be isochronous */ + if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != + USB_ENDPOINT_XFER_ISOC) + continue; + /* check direction */ + stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ? + SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; + altno = altsd->bAlternateSetting; + + if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) + continue; + + /* get audio formats */ + switch (protocol) { + default: + snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n", + dev->devnum, iface_no, altno, protocol); + protocol = UAC_VERSION_1; + /* fall through */ + + case UAC_VERSION_1: { + struct uac1_as_header_descriptor *as = + snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); + + if (!as) { + snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", + dev->devnum, iface_no, altno); + continue; + } -static const char *usb_error_string(int err) -{ - switch (err) { - case -ENODEV: - return "no device"; - case -ENOENT: - return "endpoint not enabled"; - case -EPIPE: - return "endpoint stalled"; - case -ENOSPC: - return "not enough bandwidth"; - case -ESHUTDOWN: - return "device disabled"; - case -EHOSTUNREACH: - return "device suspended"; - case -EINVAL: - case -EAGAIN: - case -EFBIG: - case -EMSGSIZE: - return "internal error"; - default: - return "unknown error"; - } -} + if (as->bLength < sizeof(*as)) { + snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", + dev->devnum, iface_no, altno); + continue; + } -/* - * set up and start data/sync urbs - */ -static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime) -{ - unsigned int i; - int err; + format = le16_to_cpu(as->wFormatTag); /* remember the format value */ + break; + } - if (subs->stream->chip->shutdown) - return -EBADFD; + case UAC_VERSION_2: { + struct uac2_input_terminal_descriptor *input_term; + struct uac2_output_terminal_descriptor *output_term; + struct uac2_as_header_descriptor *as = + snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); - for (i = 0; i < subs->nurbs; i++) { - if (snd_BUG_ON(!subs->dataurb[i].urb)) - return -EINVAL; - if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) { - snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i); - goto __error; - } - } - if (subs->syncpipe) { - for (i = 0; i < SYNC_URBS; i++) { - if (snd_BUG_ON(!subs->syncurb[i].urb)) - return -EINVAL; - if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) { - snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i); - goto __error; + if (!as) { + snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", + dev->devnum, iface_no, altno); + continue; } - } - } - subs->active_mask = 0; - subs->unlink_mask = 0; - subs->running = 1; - for (i = 0; i < subs->nurbs; i++) { - err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC); - if (err < 0) { - snd_printk(KERN_ERR "cannot submit datapipe " - "for urb %d, error %d: %s\n", - i, err, usb_error_string(err)); - goto __error; - } - set_bit(i, &subs->active_mask); - } - if (subs->syncpipe) { - for (i = 0; i < SYNC_URBS; i++) { - err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC); - if (err < 0) { - snd_printk(KERN_ERR "cannot submit syncpipe " - "for urb %d, error %d: %s\n", - i, err, usb_error_string(err)); - goto __error; + if (as->bLength < sizeof(*as)) { + snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", + dev->devnum, iface_no, altno); + continue; } - set_bit(i + 16, &subs->active_mask); - } - } - return 0; - - __error: - // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); - deactivate_urbs(subs, 0, 0); - return -EPIPE; -} + num_channels = as->bNrChannels; + format = le32_to_cpu(as->bmFormats); -/* - */ -static struct snd_urb_ops audio_urb_ops[2] = { - { - .prepare = prepare_nodata_playback_urb, - .retire = retire_playback_urb, - .prepare_sync = prepare_playback_sync_urb, - .retire_sync = retire_playback_sync_urb, - }, - { - .prepare = prepare_capture_urb, - .retire = retire_capture_urb, - .prepare_sync = prepare_capture_sync_urb, - .retire_sync = retire_capture_sync_urb, - }, -}; - -/* - * initialize the substream instance. - */ + /* lookup the terminal associated to this interface + * to extract the clock */ + input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (input_term) { + clock = input_term->bCSourceID; + break; + } -void snd_usb_init_substream(struct snd_usb_stream *as, - int stream, struct audioformat *fp) -{ - struct snd_usb_substream *subs = &as->substream[stream]; - - INIT_LIST_HEAD(&subs->fmt_list); - spin_lock_init(&subs->lock); - - subs->stream = as; - subs->direction = stream; - subs->dev = as->chip->dev; - subs->txfr_quirk = as->chip->txfr_quirk; - subs->ops = audio_urb_ops[stream]; - if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH) - subs->ops.prepare_sync = prepare_capture_sync_urb_hs; - - snd_usb_set_pcm_ops(as->pcm, stream); - - list_add_tail(&fp->list, &subs->fmt_list); - subs->formats |= fp->formats; - subs->endpoint = fp->endpoint; - subs->num_formats++; - subs->fmt_type = fp->fmt_type; -} + output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (output_term) { + clock = output_term->bCSourceID; + break; + } -int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_usb_substream *subs = substream->runtime->private_data; + snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n", + dev->devnum, iface_no, altno, as->bTerminalLink); + continue; + } + } - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - subs->ops.prepare = prepare_playback_urb; - return 0; - case SNDRV_PCM_TRIGGER_STOP: - return deactivate_urbs(subs, 0, 0); - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - subs->ops.prepare = prepare_nodata_playback_urb; - return 0; - } + /* get format type */ + fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE); + if (!fmt) { + snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n", + dev->devnum, iface_no, altno); + continue; + } + if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) || + ((protocol == UAC_VERSION_2) && (fmt->bLength != 6))) { + snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", + dev->devnum, iface_no, altno); + continue; + } - return -EINVAL; -} + /* + * Blue Microphones workaround: The last altsetting is identical + * with the previous one, except for a larger packet size, but + * is actually a mislabeled two-channel setting; ignore it. + */ + if (fmt->bNrChannels == 1 && + fmt->bSubframeSize == 2 && + altno == 2 && num == 3 && + fp && fp->altsetting == 1 && fp->channels == 1 && + fp->formats == SNDRV_PCM_FMTBIT_S16_LE && + protocol == UAC_VERSION_1 && + le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == + fp->maxpacksize * 2) + continue; + + fp = kzalloc(sizeof(*fp), GFP_KERNEL); + if (! fp) { + snd_printk(KERN_ERR "cannot malloc\n"); + return -ENOMEM; + } -int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_usb_substream *subs = substream->runtime->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - subs->ops.retire = retire_capture_urb; - return start_urbs(subs, substream->runtime); - case SNDRV_PCM_TRIGGER_STOP: - return deactivate_urbs(subs, 0, 0); - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - subs->ops.retire = retire_paused_capture_urb; - return 0; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - subs->ops.retire = retire_capture_urb; - return 0; - } + fp->iface = iface_no; + fp->altsetting = altno; + fp->altset_idx = i; + fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; + fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; + fp->datainterval = snd_usb_parse_datainterval(chip, alts); + fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); + /* num_channels is only set for v2 interfaces */ + fp->channels = num_channels; + if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) + fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) + * (fp->maxpacksize & 0x7ff); + fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); + fp->clock = clock; + + /* some quirks for attributes here */ + + switch (chip->usb_id) { + case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ + /* Optoplay sets the sample rate attribute although + * it seems not supporting it in fact. + */ + fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE; + break; + case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ + /* doesn't set the sample rate attribute, but supports it */ + fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; + break; + case USB_ID(0x0763, 0x2001): /* M-Audio Quattro USB */ + case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */ + case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ + case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is + an older model 77d:223) */ + /* + * plantronics headset and Griffin iMic have set adaptive-in + * although it's really not... + */ + fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; + else + fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; + break; + } - return -EINVAL; -} + /* ok, let's parse further... */ + if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { + kfree(fp->rate_table); + kfree(fp); + fp = NULL; + continue; + } -int snd_usb_substream_prepare(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime) -{ - /* clear urbs (to be sure) */ - deactivate_urbs(subs, 0, 1); - wait_clear_urbs(subs); - - /* for playback, submit the URBs now; otherwise, the first hwptr_done - * updates for all URBs would happen at the same time when starting */ - if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { - subs->ops.prepare = prepare_nodata_playback_urb; - return start_urbs(subs, runtime); + snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint); + err = snd_usb_add_audio_endpoint(chip, stream, fp); + if (err < 0) { + kfree(fp->rate_table); + kfree(fp); + return err; + } + /* try to set the interface... */ + usb_set_interface(chip->dev, iface_no, altno); + snd_usb_init_pitch(chip, iface_no, alts, fp); + snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max); } - return 0; } diff --git a/trunk/sound/usb/endpoint.h b/trunk/sound/usb/endpoint.h index 88eb63a636eb..64dd0db023b2 100644 --- a/trunk/sound/usb/endpoint.h +++ b/trunk/sound/usb/endpoint.h @@ -1,21 +1,11 @@ #ifndef __USBAUDIO_ENDPOINT_H #define __USBAUDIO_ENDPOINT_H -void snd_usb_init_substream(struct snd_usb_stream *as, - int stream, - struct audioformat *fp); +int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, + int iface_no); -int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, - unsigned int period_bytes, - unsigned int rate, - unsigned int frame_bits); - -void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force); - -int snd_usb_substream_prepare(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime); - -int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd); -int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd); +int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, + int stream, + struct audioformat *fp); #endif /* __USBAUDIO_ENDPOINT_H */ diff --git a/trunk/sound/usb/format.c b/trunk/sound/usb/format.c index 89421d176570..8d042dce0d16 100644 --- a/trunk/sound/usb/format.c +++ b/trunk/sound/usb/format.c @@ -286,7 +286,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, UAC2_CS_CONTROL_SAM_FREQ << 8, snd_usb_ctrl_intf(chip) | (clock << 8), - tmp, sizeof(tmp)); + tmp, sizeof(tmp), 1000); if (ret < 0) { snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n", @@ -307,7 +307,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, UAC2_CS_CONTROL_SAM_FREQ << 8, snd_usb_ctrl_intf(chip) | (clock << 8), - data, data_size); + data, data_size, 1000); if (ret < 0) { snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n", diff --git a/trunk/sound/usb/helper.c b/trunk/sound/usb/helper.c index 9eed8f40b179..f280c1903c25 100644 --- a/trunk/sound/usb/helper.c +++ b/trunk/sound/usb/helper.c @@ -81,7 +81,7 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype */ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, - __u16 size) + __u16 size, int timeout) { int err; void *buf = NULL; @@ -92,7 +92,7 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, return -ENOMEM; } err = usb_control_msg(dev, pipe, request, requesttype, - value, index, buf, size, 1000); + value, index, buf, size, timeout); if (size > 0) { memcpy(data, buf, size); kfree(buf); diff --git a/trunk/sound/usb/helper.h b/trunk/sound/usb/helper.h index 805c300dd004..09bd943c43bf 100644 --- a/trunk/sound/usb/helper.h +++ b/trunk/sound/usb/helper.h @@ -8,7 +8,7 @@ void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsub int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, - void *data, __u16 size); + void *data, __u16 size, int timeout); unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, struct usb_host_interface *alts); diff --git a/trunk/sound/usb/midi.c b/trunk/sound/usb/midi.c index e21f026d9577..f9289102886a 100644 --- a/trunk/sound/usb/midi.c +++ b/trunk/sound/usb/midi.c @@ -816,22 +816,6 @@ static struct usb_protocol_ops snd_usbmidi_raw_ops = { .output = snd_usbmidi_raw_output, }; -/* - * FTDI protocol: raw MIDI bytes, but input packets have two modem status bytes. - */ - -static void snd_usbmidi_ftdi_input(struct snd_usb_midi_in_endpoint* ep, - uint8_t* buffer, int buffer_length) -{ - if (buffer_length > 2) - snd_usbmidi_input_data(ep, 0, buffer + 2, buffer_length - 2); -} - -static struct usb_protocol_ops snd_usbmidi_ftdi_ops = { - .input = snd_usbmidi_ftdi_input, - .output = snd_usbmidi_raw_output, -}; - static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep, uint8_t *buffer, int buffer_length) { @@ -2179,17 +2163,6 @@ int snd_usbmidi_create(struct snd_card *card, /* endpoint 1 is input-only */ endpoints[1].out_cables = 0; break; - case QUIRK_MIDI_FTDI: - umidi->usb_protocol_ops = &snd_usbmidi_ftdi_ops; - - /* set baud rate to 31250 (48 MHz / 16 / 96) */ - err = usb_control_msg(umidi->dev, usb_sndctrlpipe(umidi->dev, 0), - 3, 0x40, 0x60, 0, NULL, 0, 1000); - if (err < 0) - break; - - err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); - break; default: snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); err = -ENXIO; diff --git a/trunk/sound/usb/mixer.c b/trunk/sound/usb/mixer.c index 60f65ace7474..c22fa76e363a 100644 --- a/trunk/sound/usb/mixer.c +++ b/trunk/sound/usb/mixer.c @@ -152,7 +152,6 @@ static inline void check_mapped_dB(const struct usbmix_name_map *p, if (p && p->dB) { cval->dBmin = p->dB->min; cval->dBmax = p->dB->max; - cval->initialized = 1; } } @@ -296,7 +295,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), - buf, val_len) >= val_len) { + buf, val_len, 100) >= val_len) { *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); snd_usb_autosuspend(cval->mixer->chip); return 0; @@ -333,7 +332,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), - buf, size); + buf, size, 1000); snd_usb_autosuspend(chip); if (ret < 0) { @@ -445,7 +444,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, usb_sndctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), - buf, val_len) >= 0) { + buf, val_len, 100) >= 0) { snd_usb_autosuspend(chip); return 0; } @@ -881,17 +880,8 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; } else { - if (!cval->initialized) { - get_min_max(cval, 0); - if (cval->initialized && cval->dBmin >= cval->dBmax) { - kcontrol->vd[0].access &= - ~(SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); - snd_ctl_notify(cval->mixer->chip->card, - SNDRV_CTL_EVENT_MASK_INFO, - &kcontrol->id); - } - } + if (! cval->initialized) + get_min_max(cval, 0); uinfo->value.integer.min = 0; uinfo->value.integer.max = (cval->max - cval->min + cval->res - 1) / cval->res; @@ -1102,7 +1092,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, " Switch" : " Volume"); if (control == UAC_FU_VOLUME) { check_mapped_dB(map, cval); - if (cval->dBmin < cval->dBmax || !cval->initialized) { + if (cval->dBmin < cval->dBmax) { kctl->tlv.c = mixer_vol_tlv; kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ | @@ -1201,11 +1191,6 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void if (state->mixer->protocol == UAC_VERSION_1) { csize = hdr->bControlSize; - if (!csize) { - snd_printdd(KERN_ERR "usbaudio: unit %u: " - "invalid bControlSize == 0\n", unitid); - return -EINVAL; - } channels = (hdr->bLength - 7) / csize - 1; bmaControls = hdr->bmaControls; } else { @@ -1259,7 +1244,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, 0); } } else { /* UAC_VERSION_2 */ - for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) { + for (i = 0; i < 30/2; i++) { unsigned int ch_bits = 0; unsigned int ch_read_only = 0; @@ -1949,13 +1934,15 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) struct mixer_build state; int err; const struct usbmix_ctl_map *map; + struct usb_host_interface *hostif; void *p; + hostif = mixer->chip->ctrl_intf; memset(&state, 0, sizeof(state)); state.chip = mixer->chip; state.mixer = mixer; - state.buffer = mixer->hostif->extra; - state.buflen = mixer->hostif->extralen; + state.buffer = hostif->extra; + state.buflen = hostif->extralen; /* check the mapping table */ for (map = usbmix_ctl_maps; map->id; map++) { @@ -1968,8 +1955,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) } p = NULL; - while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, mixer->hostif->extralen, - p, UAC_OUTPUT_TERMINAL)) != NULL) { + while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { if (mixer->protocol == UAC_VERSION_1) { struct uac1_output_terminal_descriptor *desc = p; @@ -2176,15 +2162,17 @@ int snd_usb_mixer_activate(struct usb_mixer_interface *mixer) /* create the handler for the optional status interrupt endpoint */ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) { + struct usb_host_interface *hostif; struct usb_endpoint_descriptor *ep; void *transfer_buffer; int buffer_length; unsigned int epnum; + hostif = mixer->chip->ctrl_intf; /* we need one interrupt input endpoint */ - if (get_iface_desc(mixer->hostif)->bNumEndpoints < 1) + if (get_iface_desc(hostif)->bNumEndpoints < 1) return 0; - ep = get_endpoint(mixer->hostif, 0); + ep = get_endpoint(hostif, 0); if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_int(ep)) return 0; @@ -2214,6 +2202,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, }; struct usb_mixer_interface *mixer; struct snd_info_entry *entry; + struct usb_host_interface *host_iface; int err; strcpy(chip->card->mixername, "USB Mixer"); @@ -2230,8 +2219,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, return -ENOMEM; } - mixer->hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; - switch (get_iface_desc(mixer->hostif)->bInterfaceProtocol) { + host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; + switch (get_iface_desc(host_iface)->bInterfaceProtocol) { case UAC_VERSION_1: default: mixer->protocol = UAC_VERSION_1; diff --git a/trunk/sound/usb/mixer.h b/trunk/sound/usb/mixer.h index 81b2d8a32fb0..ae1a14dcfe82 100644 --- a/trunk/sound/usb/mixer.h +++ b/trunk/sound/usb/mixer.h @@ -3,7 +3,6 @@ struct usb_mixer_interface { struct snd_usb_audio *chip; - struct usb_host_interface *hostif; struct list_head list; unsigned int ignore_ctl_error; struct urb *urb; diff --git a/trunk/sound/usb/mixer_quirks.c b/trunk/sound/usb/mixer_quirks.c index ab125ee0b0f0..3d0f4873112b 100644 --- a/trunk/sound/usb/mixer_quirks.c +++ b/trunk/sound/usb/mixer_quirks.c @@ -190,18 +190,18 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - !value, 0, NULL, 0); + !value, 0, NULL, 0, 100); /* USB X-Fi S51 Pro */ if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - !value, 0, NULL, 0); + !value, 0, NULL, 0, 100); else err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - value, index + 2, NULL, 0); + value, index + 2, NULL, 0, 100); if (err < 0) return err; mixer->audigy2nx_leds[index] = value; @@ -299,7 +299,7 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, usb_rcvctrlpipe(mixer->chip->dev, 0), UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, - jacks[i].unitid << 8, buf, 3); + jacks[i].unitid << 8, buf, 3, 100); if (err == 3 && (buf[0] == 3 || buf[0] == 6)) snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); else @@ -332,7 +332,7 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - 50, 0, &new_status, 1); + 50, 0, &new_status, 1, 100); if (err < 0) return err; mixer->xonar_u1_status = new_status; diff --git a/trunk/sound/usb/pcm.c b/trunk/sound/usb/pcm.c index 0220b0f335b9..b8dcbf407bbb 100644 --- a/trunk/sound/usb/pcm.c +++ b/trunk/sound/usb/pcm.c @@ -28,36 +28,12 @@ #include "card.h" #include "quirks.h" #include "debug.h" -#include "endpoint.h" +#include "urb.h" #include "helper.h" #include "pcm.h" #include "clock.h" #include "power.h" -/* return the estimated delay based on USB frame counters */ -snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, - unsigned int rate) -{ - int current_frame_number; - int frame_diff; - int est_delay; - - current_frame_number = usb_get_current_frame_number(subs->dev); - /* - * HCD implementations use different widths, use lower 8 bits. - * The delay will be managed up to 256ms, which is more than - * enough - */ - frame_diff = (current_frame_number - subs->last_frame_number) & 0xff; - - /* Approximation based on number of samples per USB frame (ms), - some truncation for 44.1 but the estimate is good enough */ - est_delay = subs->last_delay - (frame_diff * rate / 1000); - if (est_delay < 0) - est_delay = 0; - return est_delay; -} - /* * return the current pcm pointer. just based on the hwptr_done value. */ @@ -69,8 +45,6 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream subs = (struct snd_usb_substream *)substream->runtime->private_data; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; - substream->runtime->delay = snd_usb_pcm_delay(subs, - substream->runtime->rate); spin_unlock(&subs->lock); return hwptr_done / (substream->runtime->frame_bits >> 3); } @@ -152,7 +126,7 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface, if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, - data, sizeof(data))) < 0) { + data, sizeof(data), 1000)) < 0) { snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", dev->devnum, iface, ep); return err; @@ -176,7 +150,7 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface, if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, UAC2_EP_CS_PITCH << 8, 0, - data, sizeof(data))) < 0) { + data, sizeof(data), 1000)) < 0) { snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n", dev->devnum, iface, fmt->altsetting); return err; @@ -443,8 +417,6 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->hwptr_done = 0; subs->transfer_done = 0; subs->phase = 0; - subs->last_delay = 0; - subs->last_frame_number = 0; runtime->delay = 0; return snd_usb_substream_prepare(subs, runtime); diff --git a/trunk/sound/usb/pcm.h b/trunk/sound/usb/pcm.h index df7a003682ad..ed3e283f618d 100644 --- a/trunk/sound/usb/pcm.h +++ b/trunk/sound/usb/pcm.h @@ -1,9 +1,6 @@ #ifndef __USBAUDIO_PCM_H #define __USBAUDIO_PCM_H -snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, - unsigned int rate); - void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, diff --git a/trunk/sound/usb/quirks-table.h b/trunk/sound/usb/quirks-table.h index b61945f3af9e..dba0b7f11c54 100644 --- a/trunk/sound/usb/quirks-table.h +++ b/trunk/sound/usb/quirks-table.h @@ -39,17 +39,6 @@ .idProduct = prod, \ .bInterfaceClass = USB_CLASS_VENDOR_SPEC -/* FTDI devices */ -{ - USB_DEVICE(0x0403, 0xb8d8), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - /* .vendor_name = "STARR LABS", */ - /* .product_name = "Starr Labs MIDI USB device", */ - .ifnum = 0, - .type = QUIRK_MIDI_FTDI - } -}, - /* Creative/Toshiba Multimedia Center SB-0500 */ { USB_DEVICE(0x041e, 0x3048), @@ -1688,20 +1677,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, -{ - /* Added support for Roland UM-ONE which differs from UM-1 */ - USB_DEVICE(0x0582, 0x012a), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - /* .vendor_name = "ROLAND", */ - /* .product_name = "UM-ONE", */ - .ifnum = 0, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const struct snd_usb_midi_endpoint_info) { - .out_cables = 0x0001, - .in_cables = 0x0003 - } - } -}, { USB_DEVICE(0x0582, 0x011e), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -1732,40 +1707,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, -{ - USB_DEVICE(0x0582, 0x0130), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - /* .vendor_name = "BOSS", */ - /* .product_name = "MICRO BR-80", */ - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_COMPOSITE, - .data = (const struct snd_usb_audio_quirk[]) { - { - .ifnum = 0, - .type = QUIRK_IGNORE_INTERFACE - }, - { - .ifnum = 1, - .type = QUIRK_AUDIO_STANDARD_INTERFACE - }, - { - .ifnum = 2, - .type = QUIRK_AUDIO_STANDARD_INTERFACE - }, - { - .ifnum = 3, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const struct snd_usb_midi_endpoint_info) { - .out_cables = 0x0001, - .in_cables = 0x0001 - } - }, - { - .ifnum = -1 - } - } - } -}, /* Guillemot devices */ { @@ -2476,12 +2417,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), .idProduct = 0x1020, }, -/* KeithMcMillen Stringport */ -{ - USB_DEVICE(0x1f38, 0x0001), - .bInterfaceClass = USB_CLASS_AUDIO, -}, - /* Miditech devices */ { USB_DEVICE(0x4752, 0x0011), diff --git a/trunk/sound/usb/quirks.c b/trunk/sound/usb/quirks.c index 2e5bc7344026..77762c99afbe 100644 --- a/trunk/sound/usb/quirks.c +++ b/trunk/sound/usb/quirks.c @@ -34,7 +34,6 @@ #include "endpoint.h" #include "pcm.h" #include "clock.h" -#include "stream.h" /* * handle the quirks for the contained interfaces @@ -107,7 +106,7 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip, alts = &iface->altsetting[0]; altsd = get_iface_desc(alts); - err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber); + err = snd_usb_parse_audio_endpoints(chip, altsd->bInterfaceNumber); if (err < 0) { snd_printk(KERN_ERR "cannot setup if %d: error %d\n", altsd->bInterfaceNumber, err); @@ -148,7 +147,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, stream = (fp->endpoint & USB_DIR_IN) ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - err = snd_usb_add_audio_stream(chip, stream, fp); + err = snd_usb_add_audio_endpoint(chip, stream, fp); if (err < 0) { kfree(fp); kfree(rate_table); @@ -255,7 +254,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, stream = (fp->endpoint & USB_DIR_IN) ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - err = snd_usb_add_audio_stream(chip, stream, fp); + err = snd_usb_add_audio_endpoint(chip, stream, fp); if (err < 0) { kfree(fp); return err; @@ -307,7 +306,6 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, [QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_MIDI_AKAI] = create_any_midi_quirk, - [QUIRK_MIDI_FTDI] = create_any_midi_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, @@ -340,7 +338,7 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac snd_printdd("sending Extigy boot sequence...\n"); /* Send message to force it to reconnect with full interface. */ err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0), - 0x10, 0x43, 0x0001, 0x000a, NULL, 0); + 0x10, 0x43, 0x0001, 0x000a, NULL, 0, 1000); if (err < 0) snd_printdd("error sending boot message: %d\n", err); err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor)); @@ -361,11 +359,11 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, - 0, 0, &buf, 1); + 0, 0, &buf, 1, 1000); if (buf == 0) { snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - 1, 2000, NULL, 0); + 1, 2000, NULL, 0, 1000); return -ENODEV; } return 0; @@ -408,7 +406,7 @@ static int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 valu buf[3] = reg; return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - 0, 0, &buf, 4); + 0, 0, &buf, 4, 1000); } static int snd_usb_cm106_boot_quirk(struct usb_device *dev) @@ -428,7 +426,7 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev) */ static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) { - int err = 0, reg; + int err, reg; int val[] = {0x2004, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; for (reg = 0; reg < ARRAY_SIZE(val); reg++) { diff --git a/trunk/sound/usb/stream.c b/trunk/sound/usb/stream.c deleted file mode 100644 index 5ff8010b2d6f..000000000000 --- a/trunk/sound/usb/stream.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include - -#include -#include - -#include "usbaudio.h" -#include "card.h" -#include "proc.h" -#include "quirks.h" -#include "endpoint.h" -#include "pcm.h" -#include "helper.h" -#include "format.h" -#include "clock.h" -#include "stream.h" - -/* - * free a substream - */ -static void free_substream(struct snd_usb_substream *subs) -{ - struct list_head *p, *n; - - if (!subs->num_formats) - return; /* not initialized */ - list_for_each_safe(p, n, &subs->fmt_list) { - struct audioformat *fp = list_entry(p, struct audioformat, list); - kfree(fp->rate_table); - kfree(fp); - } - kfree(subs->rate_list.list); -} - - -/* - * free a usb stream instance - */ -static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) -{ - free_substream(&stream->substream[0]); - free_substream(&stream->substream[1]); - list_del(&stream->list); - kfree(stream); -} - -static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) -{ - struct snd_usb_stream *stream = pcm->private_data; - if (stream) { - stream->pcm = NULL; - snd_usb_audio_stream_free(stream); - } -} - - -/* - * add this endpoint to the chip instance. - * if a stream with the same endpoint already exists, append to it. - * if not, create a new pcm stream. - */ -int snd_usb_add_audio_stream(struct snd_usb_audio *chip, - int stream, - struct audioformat *fp) -{ - struct list_head *p; - struct snd_usb_stream *as; - struct snd_usb_substream *subs; - struct snd_pcm *pcm; - int err; - - list_for_each(p, &chip->pcm_list) { - as = list_entry(p, struct snd_usb_stream, list); - if (as->fmt_type != fp->fmt_type) - continue; - subs = &as->substream[stream]; - if (!subs->endpoint) - continue; - if (subs->endpoint == fp->endpoint) { - list_add_tail(&fp->list, &subs->fmt_list); - subs->num_formats++; - subs->formats |= fp->formats; - return 0; - } - } - /* look for an empty stream */ - list_for_each(p, &chip->pcm_list) { - as = list_entry(p, struct snd_usb_stream, list); - if (as->fmt_type != fp->fmt_type) - continue; - subs = &as->substream[stream]; - if (subs->endpoint) - continue; - err = snd_pcm_new_stream(as->pcm, stream, 1); - if (err < 0) - return err; - snd_usb_init_substream(as, stream, fp); - return 0; - } - - /* create a new pcm */ - as = kzalloc(sizeof(*as), GFP_KERNEL); - if (!as) - return -ENOMEM; - as->pcm_index = chip->pcm_devs; - as->chip = chip; - as->fmt_type = fp->fmt_type; - err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs, - stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0, - stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1, - &pcm); - if (err < 0) { - kfree(as); - return err; - } - as->pcm = pcm; - pcm->private_data = as; - pcm->private_free = snd_usb_audio_pcm_free; - pcm->info_flags = 0; - if (chip->pcm_devs > 0) - sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); - else - strcpy(pcm->name, "USB Audio"); - - snd_usb_init_substream(as, stream, fp); - - list_add(&as->list, &chip->pcm_list); - chip->pcm_devs++; - - snd_usb_proc_pcm_format_add(as); - - return 0; -} - -static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, - struct usb_host_interface *alts, - int protocol, int iface_no) -{ - /* parsed with a v1 header here. that's ok as we only look at the - * header first which is the same for both versions */ - struct uac_iso_endpoint_descriptor *csep; - struct usb_interface_descriptor *altsd = get_iface_desc(alts); - int attributes = 0; - - csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT); - - /* Creamware Noah has this descriptor after the 2nd endpoint */ - if (!csep && altsd->bNumEndpoints >= 2) - csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); - - if (!csep || csep->bLength < 7 || - csep->bDescriptorSubtype != UAC_EP_GENERAL) { - snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" - " class specific endpoint descriptor\n", - chip->dev->devnum, iface_no, - altsd->bAlternateSetting); - return 0; - } - - if (protocol == UAC_VERSION_1) { - attributes = csep->bmAttributes; - } else { - struct uac2_iso_endpoint_descriptor *csep2 = - (struct uac2_iso_endpoint_descriptor *) csep; - - attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX; - - /* emulate the endpoint attributes of a v1 device */ - if (csep2->bmControls & UAC2_CONTROL_PITCH) - attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL; - } - - return attributes; -} - -static struct uac2_input_terminal_descriptor * - snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id) -{ - struct uac2_input_terminal_descriptor *term = NULL; - - while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, - ctrl_iface->extralen, - term, UAC_INPUT_TERMINAL))) { - if (term->bTerminalID == terminal_id) - return term; - } - - return NULL; -} - -static struct uac2_output_terminal_descriptor * - snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id) -{ - struct uac2_output_terminal_descriptor *term = NULL; - - while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, - ctrl_iface->extralen, - term, UAC_OUTPUT_TERMINAL))) { - if (term->bTerminalID == terminal_id) - return term; - } - - return NULL; -} - -int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) -{ - struct usb_device *dev; - struct usb_interface *iface; - struct usb_host_interface *alts; - struct usb_interface_descriptor *altsd; - int i, altno, err, stream; - int format = 0, num_channels = 0; - struct audioformat *fp = NULL; - int num, protocol, clock = 0; - struct uac_format_type_i_continuous_descriptor *fmt; - - dev = chip->dev; - - /* parse the interface's altsettings */ - iface = usb_ifnum_to_if(dev, iface_no); - - num = iface->num_altsetting; - - /* - * Dallas DS4201 workaround: It presents 5 altsettings, but the last - * one misses syncpipe, and does not produce any sound. - */ - if (chip->usb_id == USB_ID(0x04fa, 0x4201)) - num = 4; - - for (i = 0; i < num; i++) { - alts = &iface->altsetting[i]; - altsd = get_iface_desc(alts); - protocol = altsd->bInterfaceProtocol; - /* skip invalid one */ - if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && - altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || - (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING && - altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || - altsd->bNumEndpoints < 1 || - le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) - continue; - /* must be isochronous */ - if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != - USB_ENDPOINT_XFER_ISOC) - continue; - /* check direction */ - stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ? - SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - altno = altsd->bAlternateSetting; - - if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) - continue; - - /* get audio formats */ - switch (protocol) { - default: - snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n", - dev->devnum, iface_no, altno, protocol); - protocol = UAC_VERSION_1; - /* fall through */ - - case UAC_VERSION_1: { - struct uac1_as_header_descriptor *as = - snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); - - if (!as) { - snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", - dev->devnum, iface_no, altno); - continue; - } - - if (as->bLength < sizeof(*as)) { - snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", - dev->devnum, iface_no, altno); - continue; - } - - format = le16_to_cpu(as->wFormatTag); /* remember the format value */ - break; - } - - case UAC_VERSION_2: { - struct uac2_input_terminal_descriptor *input_term; - struct uac2_output_terminal_descriptor *output_term; - struct uac2_as_header_descriptor *as = - snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); - - if (!as) { - snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", - dev->devnum, iface_no, altno); - continue; - } - - if (as->bLength < sizeof(*as)) { - snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", - dev->devnum, iface_no, altno); - continue; - } - - num_channels = as->bNrChannels; - format = le32_to_cpu(as->bmFormats); - - /* lookup the terminal associated to this interface - * to extract the clock */ - input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (input_term) { - clock = input_term->bCSourceID; - break; - } - - output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (output_term) { - clock = output_term->bCSourceID; - break; - } - - snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n", - dev->devnum, iface_no, altno, as->bTerminalLink); - continue; - } - } - - /* get format type */ - fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE); - if (!fmt) { - snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n", - dev->devnum, iface_no, altno); - continue; - } - if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) || - ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) { - snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", - dev->devnum, iface_no, altno); - continue; - } - - /* - * Blue Microphones workaround: The last altsetting is identical - * with the previous one, except for a larger packet size, but - * is actually a mislabeled two-channel setting; ignore it. - */ - if (fmt->bNrChannels == 1 && - fmt->bSubframeSize == 2 && - altno == 2 && num == 3 && - fp && fp->altsetting == 1 && fp->channels == 1 && - fp->formats == SNDRV_PCM_FMTBIT_S16_LE && - protocol == UAC_VERSION_1 && - le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == - fp->maxpacksize * 2) - continue; - - fp = kzalloc(sizeof(*fp), GFP_KERNEL); - if (! fp) { - snd_printk(KERN_ERR "cannot malloc\n"); - return -ENOMEM; - } - - fp->iface = iface_no; - fp->altsetting = altno; - fp->altset_idx = i; - fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; - fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; - fp->datainterval = snd_usb_parse_datainterval(chip, alts); - fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - /* num_channels is only set for v2 interfaces */ - fp->channels = num_channels; - if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) - fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) - * (fp->maxpacksize & 0x7ff); - fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); - fp->clock = clock; - - /* some quirks for attributes here */ - - switch (chip->usb_id) { - case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ - /* Optoplay sets the sample rate attribute although - * it seems not supporting it in fact. - */ - fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE; - break; - case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ - case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ - /* doesn't set the sample rate attribute, but supports it */ - fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; - break; - case USB_ID(0x0763, 0x2001): /* M-Audio Quattro USB */ - case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */ - case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ - case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is - an older model 77d:223) */ - /* - * plantronics headset and Griffin iMic have set adaptive-in - * although it's really not... - */ - fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; - else - fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; - break; - } - - /* ok, let's parse further... */ - if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { - kfree(fp->rate_table); - kfree(fp); - fp = NULL; - continue; - } - - snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint); - err = snd_usb_add_audio_stream(chip, stream, fp); - if (err < 0) { - kfree(fp->rate_table); - kfree(fp); - return err; - } - /* try to set the interface... */ - usb_set_interface(chip->dev, iface_no, altno); - snd_usb_init_pitch(chip, iface_no, alts, fp); - snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max); - } - return 0; -} - diff --git a/trunk/sound/usb/stream.h b/trunk/sound/usb/stream.h deleted file mode 100644 index c97f679fc84f..000000000000 --- a/trunk/sound/usb/stream.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __USBAUDIO_STREAM_H -#define __USBAUDIO_STREAM_H - -int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, - int iface_no); - -int snd_usb_add_audio_stream(struct snd_usb_audio *chip, - int stream, - struct audioformat *fp); - -#endif /* __USBAUDIO_STREAM_H */ - diff --git a/trunk/sound/usb/urb.c b/trunk/sound/usb/urb.c new file mode 100644 index 000000000000..e184349aee83 --- /dev/null +++ b/trunk/sound/usb/urb.c @@ -0,0 +1,941 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include + +#include +#include + +#include "usbaudio.h" +#include "helper.h" +#include "card.h" +#include "urb.h" +#include "pcm.h" + +/* + * convert a sampling rate into our full speed format (fs/1000 in Q16.16) + * this will overflow at approx 524 kHz + */ +static inline unsigned get_usb_full_speed_rate(unsigned int rate) +{ + return ((rate << 13) + 62) / 125; +} + +/* + * convert a sampling rate into USB high speed format (fs/8000 in Q16.16) + * this will overflow at approx 4 MHz + */ +static inline unsigned get_usb_high_speed_rate(unsigned int rate) +{ + return ((rate << 10) + 62) / 125; +} + +/* + * unlink active urbs. + */ +static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep) +{ + struct snd_usb_audio *chip = subs->stream->chip; + unsigned int i; + int async; + + subs->running = 0; + + if (!force && subs->stream->chip->shutdown) /* to be sure... */ + return -EBADFD; + + async = !can_sleep && chip->async_unlink; + + if (!async && in_interrupt()) + return 0; + + for (i = 0; i < subs->nurbs; i++) { + if (test_bit(i, &subs->active_mask)) { + if (!test_and_set_bit(i, &subs->unlink_mask)) { + struct urb *u = subs->dataurb[i].urb; + if (async) + usb_unlink_urb(u); + else + usb_kill_urb(u); + } + } + } + if (subs->syncpipe) { + for (i = 0; i < SYNC_URBS; i++) { + if (test_bit(i+16, &subs->active_mask)) { + if (!test_and_set_bit(i+16, &subs->unlink_mask)) { + struct urb *u = subs->syncurb[i].urb; + if (async) + usb_unlink_urb(u); + else + usb_kill_urb(u); + } + } + } + } + return 0; +} + + +/* + * release a urb data + */ +static void release_urb_ctx(struct snd_urb_ctx *u) +{ + if (u->urb) { + if (u->buffer_size) + usb_free_coherent(u->subs->dev, u->buffer_size, + u->urb->transfer_buffer, + u->urb->transfer_dma); + usb_free_urb(u->urb); + u->urb = NULL; + } +} + +/* + * wait until all urbs are processed. + */ +static int wait_clear_urbs(struct snd_usb_substream *subs) +{ + unsigned long end_time = jiffies + msecs_to_jiffies(1000); + unsigned int i; + int alive; + + do { + alive = 0; + for (i = 0; i < subs->nurbs; i++) { + if (test_bit(i, &subs->active_mask)) + alive++; + } + if (subs->syncpipe) { + for (i = 0; i < SYNC_URBS; i++) { + if (test_bit(i + 16, &subs->active_mask)) + alive++; + } + } + if (! alive) + break; + schedule_timeout_uninterruptible(1); + } while (time_before(jiffies, end_time)); + if (alive) + snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); + return 0; +} + +/* + * release a substream + */ +void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force) +{ + int i; + + /* stop urbs (to be sure) */ + deactivate_urbs(subs, force, 1); + wait_clear_urbs(subs); + + for (i = 0; i < MAX_URBS; i++) + release_urb_ctx(&subs->dataurb[i]); + for (i = 0; i < SYNC_URBS; i++) + release_urb_ctx(&subs->syncurb[i]); + usb_free_coherent(subs->dev, SYNC_URBS * 4, + subs->syncbuf, subs->sync_dma); + subs->syncbuf = NULL; + subs->nurbs = 0; +} + +/* + * complete callback from data urb + */ +static void snd_complete_urb(struct urb *urb) +{ + struct snd_urb_ctx *ctx = urb->context; + struct snd_usb_substream *subs = ctx->subs; + struct snd_pcm_substream *substream = ctx->subs->pcm_substream; + int err = 0; + + if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) || + !subs->running || /* can be stopped during retire callback */ + (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || + (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + clear_bit(ctx->index, &subs->active_mask); + if (err < 0) { + snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + } + } +} + + +/* + * complete callback from sync urb + */ +static void snd_complete_sync_urb(struct urb *urb) +{ + struct snd_urb_ctx *ctx = urb->context; + struct snd_usb_substream *subs = ctx->subs; + struct snd_pcm_substream *substream = ctx->subs->pcm_substream; + int err = 0; + + if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) || + !subs->running || /* can be stopped during retire callback */ + (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || + (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + clear_bit(ctx->index + 16, &subs->active_mask); + if (err < 0) { + snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + } + } +} + + +/* + * initialize a substream for plaback/capture + */ +int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, + unsigned int period_bytes, + unsigned int rate, + unsigned int frame_bits) +{ + unsigned int maxsize, i; + int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; + unsigned int urb_packs, total_packs, packs_per_ms; + struct snd_usb_audio *chip = subs->stream->chip; + + /* calculate the frequency in 16.16 format */ + if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) + subs->freqn = get_usb_full_speed_rate(rate); + else + subs->freqn = get_usb_high_speed_rate(rate); + subs->freqm = subs->freqn; + subs->freqshift = INT_MIN; + /* calculate max. frequency */ + if (subs->maxpacksize) { + /* whatever fits into a max. size packet */ + maxsize = subs->maxpacksize; + subs->freqmax = (maxsize / (frame_bits >> 3)) + << (16 - subs->datainterval); + } else { + /* no max. packet size: just take 25% higher than nominal */ + subs->freqmax = subs->freqn + (subs->freqn >> 2); + maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) + >> (16 - subs->datainterval); + } + subs->phase = 0; + + if (subs->fill_max) + subs->curpacksize = subs->maxpacksize; + else + subs->curpacksize = maxsize; + + if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) + packs_per_ms = 8 >> subs->datainterval; + else + packs_per_ms = 1; + + if (is_playback) { + urb_packs = max(chip->nrpacks, 1); + urb_packs = min(urb_packs, (unsigned int)MAX_PACKS); + } else + urb_packs = 1; + urb_packs *= packs_per_ms; + if (subs->syncpipe) + urb_packs = min(urb_packs, 1U << subs->syncinterval); + + /* decide how many packets to be used */ + if (is_playback) { + unsigned int minsize, maxpacks; + /* determine how small a packet can be */ + minsize = (subs->freqn >> (16 - subs->datainterval)) + * (frame_bits >> 3); + /* with sync from device, assume it can be 12% lower */ + if (subs->syncpipe) + minsize -= minsize >> 3; + minsize = max(minsize, 1u); + total_packs = (period_bytes + minsize - 1) / minsize; + /* we need at least two URBs for queueing */ + if (total_packs < 2) { + total_packs = 2; + } else { + /* and we don't want too long a queue either */ + maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2); + total_packs = min(total_packs, maxpacks); + } + } else { + while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) + urb_packs >>= 1; + total_packs = MAX_URBS * urb_packs; + } + subs->nurbs = (total_packs + urb_packs - 1) / urb_packs; + if (subs->nurbs > MAX_URBS) { + /* too much... */ + subs->nurbs = MAX_URBS; + total_packs = MAX_URBS * urb_packs; + } else if (subs->nurbs < 2) { + /* too little - we need at least two packets + * to ensure contiguous playback/capture + */ + subs->nurbs = 2; + } + + /* allocate and initialize data urbs */ + for (i = 0; i < subs->nurbs; i++) { + struct snd_urb_ctx *u = &subs->dataurb[i]; + u->index = i; + u->subs = subs; + u->packets = (i + 1) * total_packs / subs->nurbs + - i * total_packs / subs->nurbs; + u->buffer_size = maxsize * u->packets; + if (subs->fmt_type == UAC_FORMAT_TYPE_II) + u->packets++; /* for transfer delimiter */ + u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); + if (!u->urb) + goto out_of_memory; + u->urb->transfer_buffer = + usb_alloc_coherent(subs->dev, u->buffer_size, + GFP_KERNEL, &u->urb->transfer_dma); + if (!u->urb->transfer_buffer) + goto out_of_memory; + u->urb->pipe = subs->datapipe; + u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + u->urb->interval = 1 << subs->datainterval; + u->urb->context = u; + u->urb->complete = snd_complete_urb; + } + + if (subs->syncpipe) { + /* allocate and initialize sync urbs */ + subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4, + GFP_KERNEL, &subs->sync_dma); + if (!subs->syncbuf) + goto out_of_memory; + for (i = 0; i < SYNC_URBS; i++) { + struct snd_urb_ctx *u = &subs->syncurb[i]; + u->index = i; + u->subs = subs; + u->packets = 1; + u->urb = usb_alloc_urb(1, GFP_KERNEL); + if (!u->urb) + goto out_of_memory; + u->urb->transfer_buffer = subs->syncbuf + i * 4; + u->urb->transfer_dma = subs->sync_dma + i * 4; + u->urb->transfer_buffer_length = 4; + u->urb->pipe = subs->syncpipe; + u->urb->transfer_flags = URB_ISO_ASAP | + URB_NO_TRANSFER_DMA_MAP; + u->urb->number_of_packets = 1; + u->urb->interval = 1 << subs->syncinterval; + u->urb->context = u; + u->urb->complete = snd_complete_sync_urb; + } + } + return 0; + +out_of_memory: + snd_usb_release_substream_urbs(subs, 0); + return -ENOMEM; +} + +/* + * prepare urb for full speed capture sync pipe + * + * fill the length and offset of each urb descriptor. + * the fixed 10.14 frequency is passed through the pipe. + */ +static int prepare_capture_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + unsigned char *cp = urb->transfer_buffer; + struct snd_urb_ctx *ctx = urb->context; + + urb->dev = ctx->subs->dev; /* we need to set this at each time */ + urb->iso_frame_desc[0].length = 3; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn >> 2; + cp[1] = subs->freqn >> 10; + cp[2] = subs->freqn >> 18; + return 0; +} + +/* + * prepare urb for high speed capture sync pipe + * + * fill the length and offset of each urb descriptor. + * the fixed 12.13 frequency is passed as 16.16 through the pipe. + */ +static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + unsigned char *cp = urb->transfer_buffer; + struct snd_urb_ctx *ctx = urb->context; + + urb->dev = ctx->subs->dev; /* we need to set this at each time */ + urb->iso_frame_desc[0].length = 4; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn; + cp[1] = subs->freqn >> 8; + cp[2] = subs->freqn >> 16; + cp[3] = subs->freqn >> 24; + return 0; +} + +/* + * process after capture sync complete + * - nothing to do + */ +static int retire_capture_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + return 0; +} + +/* + * prepare urb for capture data pipe + * + * fill the offset and length of each descriptor. + * + * we use a temporary buffer to write the captured data. + * since the length of written data is determined by host, we cannot + * write onto the pcm buffer directly... the data is thus copied + * later at complete callback to the global buffer. + */ +static int prepare_capture_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + int i, offs; + struct snd_urb_ctx *ctx = urb->context; + + offs = 0; + urb->dev = ctx->subs->dev; /* we need to set this at each time */ + for (i = 0; i < ctx->packets; i++) { + urb->iso_frame_desc[i].offset = offs; + urb->iso_frame_desc[i].length = subs->curpacksize; + offs += subs->curpacksize; + } + urb->transfer_buffer_length = offs; + urb->number_of_packets = ctx->packets; + return 0; +} + +/* + * process after capture complete + * + * copy the data from each desctiptor to the pcm buffer, and + * update the current position. + */ +static int retire_capture_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + unsigned long flags; + unsigned char *cp; + int i; + unsigned int stride, frames, bytes, oldptr; + int period_elapsed = 0; + + stride = runtime->frame_bits >> 3; + + for (i = 0; i < urb->number_of_packets; i++) { + cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; + if (urb->iso_frame_desc[i].status) { + snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); + // continue; + } + bytes = urb->iso_frame_desc[i].actual_length; + frames = bytes / stride; + if (!subs->txfr_quirk) + bytes = frames * stride; + if (bytes % (runtime->sample_bits >> 3) != 0) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + int oldbytes = bytes; +#endif + bytes = frames * stride; + snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", + oldbytes, bytes); + } + /* update the current pointer */ + spin_lock_irqsave(&subs->lock, flags); + oldptr = subs->hwptr_done; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; + frames = (bytes + (oldptr % stride)) / stride; + subs->transfer_done += frames; + if (subs->transfer_done >= runtime->period_size) { + subs->transfer_done -= runtime->period_size; + period_elapsed = 1; + } + spin_unlock_irqrestore(&subs->lock, flags); + /* copy a data chunk */ + if (oldptr + bytes > runtime->buffer_size * stride) { + unsigned int bytes1 = + runtime->buffer_size * stride - oldptr; + memcpy(runtime->dma_area + oldptr, cp, bytes1); + memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); + } else { + memcpy(runtime->dma_area + oldptr, cp, bytes); + } + } + if (period_elapsed) + snd_pcm_period_elapsed(subs->pcm_substream); + return 0; +} + +/* + * Process after capture complete when paused. Nothing to do. + */ +static int retire_paused_capture_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + return 0; +} + + +/* + * prepare urb for playback sync pipe + * + * set up the offset and length to receive the current frequency. + */ +static int prepare_playback_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + struct snd_urb_ctx *ctx = urb->context; + + urb->dev = ctx->subs->dev; /* we need to set this at each time */ + urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize); + urb->iso_frame_desc[0].offset = 0; + return 0; +} + +/* + * process after playback sync complete + * + * Full speed devices report feedback values in 10.14 format as samples per + * frame, high speed devices in 16.16 format as samples per microframe. + * Because the Audio Class 1 spec was written before USB 2.0, many high speed + * devices use a wrong interpretation, some others use an entirely different + * format. Therefore, we cannot predict what format any particular device uses + * and must detect it automatically. + */ +static int retire_playback_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + unsigned int f; + int shift; + unsigned long flags; + + if (urb->iso_frame_desc[0].status != 0 || + urb->iso_frame_desc[0].actual_length < 3) + return 0; + + f = le32_to_cpup(urb->transfer_buffer); + if (urb->iso_frame_desc[0].actual_length == 3) + f &= 0x00ffffff; + else + f &= 0x0fffffff; + if (f == 0) + return 0; + + if (unlikely(subs->freqshift == INT_MIN)) { + /* + * The first time we see a feedback value, determine its format + * by shifting it left or right until it matches the nominal + * frequency value. This assumes that the feedback does not + * differ from the nominal value more than +50% or -25%. + */ + shift = 0; + while (f < subs->freqn - subs->freqn / 4) { + f <<= 1; + shift++; + } + while (f > subs->freqn + subs->freqn / 2) { + f >>= 1; + shift--; + } + subs->freqshift = shift; + } + else if (subs->freqshift >= 0) + f <<= subs->freqshift; + else + f >>= -subs->freqshift; + + if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) { + /* + * If the frequency looks valid, set it. + * This value is referred to in prepare_playback_urb(). + */ + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); + } else { + /* + * Out of range; maybe the shift value is wrong. + * Reset it so that we autodetect again the next time. + */ + subs->freqshift = INT_MIN; + } + + return 0; +} + +/* determine the number of frames in the next packet */ +static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) +{ + if (subs->fill_max) + return subs->maxframesize; + else { + subs->phase = (subs->phase & 0xffff) + + (subs->freqm << subs->datainterval); + return min(subs->phase >> 16, subs->maxframesize); + } +} + +/* + * Prepare urb for streaming before playback starts or when paused. + * + * We don't have any data, so we send silence. + */ +static int prepare_nodata_playback_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + unsigned int i, offs, counts; + struct snd_urb_ctx *ctx = urb->context; + int stride = runtime->frame_bits >> 3; + + offs = 0; + urb->dev = ctx->subs->dev; + for (i = 0; i < ctx->packets; ++i) { + counts = snd_usb_audio_next_packet_size(subs); + urb->iso_frame_desc[i].offset = offs * stride; + urb->iso_frame_desc[i].length = counts * stride; + offs += counts; + } + urb->number_of_packets = ctx->packets; + urb->transfer_buffer_length = offs * stride; + memset(urb->transfer_buffer, + runtime->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0, + offs * stride); + return 0; +} + +/* + * prepare urb for playback data pipe + * + * Since a URB can handle only a single linear buffer, we must use double + * buffering when the data to be transferred overflows the buffer boundary. + * To avoid inconsistencies when updating hwptr_done, we use double buffering + * for all URBs. + */ +static int prepare_playback_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + int i, stride; + unsigned int counts, frames, bytes; + unsigned long flags; + int period_elapsed = 0; + struct snd_urb_ctx *ctx = urb->context; + + stride = runtime->frame_bits >> 3; + + frames = 0; + urb->dev = ctx->subs->dev; /* we need to set this at each time */ + urb->number_of_packets = 0; + spin_lock_irqsave(&subs->lock, flags); + for (i = 0; i < ctx->packets; i++) { + counts = snd_usb_audio_next_packet_size(subs); + /* set up descriptor */ + urb->iso_frame_desc[i].offset = frames * stride; + urb->iso_frame_desc[i].length = counts * stride; + frames += counts; + urb->number_of_packets++; + subs->transfer_done += counts; + if (subs->transfer_done >= runtime->period_size) { + subs->transfer_done -= runtime->period_size; + period_elapsed = 1; + if (subs->fmt_type == UAC_FORMAT_TYPE_II) { + if (subs->transfer_done > 0) { + /* FIXME: fill-max mode is not + * supported yet */ + frames -= subs->transfer_done; + counts -= subs->transfer_done; + urb->iso_frame_desc[i].length = + counts * stride; + subs->transfer_done = 0; + } + i++; + if (i < ctx->packets) { + /* add a transfer delimiter */ + urb->iso_frame_desc[i].offset = + frames * stride; + urb->iso_frame_desc[i].length = 0; + urb->number_of_packets++; + } + break; + } + } + if (period_elapsed) /* finish at the period boundary */ + break; + } + bytes = frames * stride; + if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { + /* err, the transferred area goes over buffer boundary. */ + unsigned int bytes1 = + runtime->buffer_size * stride - subs->hwptr_done; + memcpy(urb->transfer_buffer, + runtime->dma_area + subs->hwptr_done, bytes1); + memcpy(urb->transfer_buffer + bytes1, + runtime->dma_area, bytes - bytes1); + } else { + memcpy(urb->transfer_buffer, + runtime->dma_area + subs->hwptr_done, bytes); + } + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; + runtime->delay += frames; + spin_unlock_irqrestore(&subs->lock, flags); + urb->transfer_buffer_length = bytes; + if (period_elapsed) + snd_pcm_period_elapsed(subs->pcm_substream); + return 0; +} + +/* + * process after playback data complete + * - decrease the delay count again + */ +static int retire_playback_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + unsigned long flags; + int stride = runtime->frame_bits >> 3; + int processed = urb->transfer_buffer_length / stride; + + spin_lock_irqsave(&subs->lock, flags); + if (processed > runtime->delay) + runtime->delay = 0; + else + runtime->delay -= processed; + spin_unlock_irqrestore(&subs->lock, flags); + return 0; +} + +static const char *usb_error_string(int err) +{ + switch (err) { + case -ENODEV: + return "no device"; + case -ENOENT: + return "endpoint not enabled"; + case -EPIPE: + return "endpoint stalled"; + case -ENOSPC: + return "not enough bandwidth"; + case -ESHUTDOWN: + return "device disabled"; + case -EHOSTUNREACH: + return "device suspended"; + case -EINVAL: + case -EAGAIN: + case -EFBIG: + case -EMSGSIZE: + return "internal error"; + default: + return "unknown error"; + } +} + +/* + * set up and start data/sync urbs + */ +static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime) +{ + unsigned int i; + int err; + + if (subs->stream->chip->shutdown) + return -EBADFD; + + for (i = 0; i < subs->nurbs; i++) { + if (snd_BUG_ON(!subs->dataurb[i].urb)) + return -EINVAL; + if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) { + snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i); + goto __error; + } + } + if (subs->syncpipe) { + for (i = 0; i < SYNC_URBS; i++) { + if (snd_BUG_ON(!subs->syncurb[i].urb)) + return -EINVAL; + if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) { + snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i); + goto __error; + } + } + } + + subs->active_mask = 0; + subs->unlink_mask = 0; + subs->running = 1; + for (i = 0; i < subs->nurbs; i++) { + err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC); + if (err < 0) { + snd_printk(KERN_ERR "cannot submit datapipe " + "for urb %d, error %d: %s\n", + i, err, usb_error_string(err)); + goto __error; + } + set_bit(i, &subs->active_mask); + } + if (subs->syncpipe) { + for (i = 0; i < SYNC_URBS; i++) { + err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC); + if (err < 0) { + snd_printk(KERN_ERR "cannot submit syncpipe " + "for urb %d, error %d: %s\n", + i, err, usb_error_string(err)); + goto __error; + } + set_bit(i + 16, &subs->active_mask); + } + } + return 0; + + __error: + // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); + deactivate_urbs(subs, 0, 0); + return -EPIPE; +} + + +/* + */ +static struct snd_urb_ops audio_urb_ops[2] = { + { + .prepare = prepare_nodata_playback_urb, + .retire = retire_playback_urb, + .prepare_sync = prepare_playback_sync_urb, + .retire_sync = retire_playback_sync_urb, + }, + { + .prepare = prepare_capture_urb, + .retire = retire_capture_urb, + .prepare_sync = prepare_capture_sync_urb, + .retire_sync = retire_capture_sync_urb, + }, +}; + +/* + * initialize the substream instance. + */ + +void snd_usb_init_substream(struct snd_usb_stream *as, + int stream, struct audioformat *fp) +{ + struct snd_usb_substream *subs = &as->substream[stream]; + + INIT_LIST_HEAD(&subs->fmt_list); + spin_lock_init(&subs->lock); + + subs->stream = as; + subs->direction = stream; + subs->dev = as->chip->dev; + subs->txfr_quirk = as->chip->txfr_quirk; + subs->ops = audio_urb_ops[stream]; + if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH) + subs->ops.prepare_sync = prepare_capture_sync_urb_hs; + + snd_usb_set_pcm_ops(as->pcm, stream); + + list_add_tail(&fp->list, &subs->fmt_list); + subs->formats |= fp->formats; + subs->endpoint = fp->endpoint; + subs->num_formats++; + subs->fmt_type = fp->fmt_type; +} + +int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_usb_substream *subs = substream->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + subs->ops.prepare = prepare_playback_urb; + return 0; + case SNDRV_PCM_TRIGGER_STOP: + return deactivate_urbs(subs, 0, 0); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + subs->ops.prepare = prepare_nodata_playback_urb; + return 0; + } + + return -EINVAL; +} + +int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_usb_substream *subs = substream->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + subs->ops.retire = retire_capture_urb; + return start_urbs(subs, substream->runtime); + case SNDRV_PCM_TRIGGER_STOP: + return deactivate_urbs(subs, 0, 0); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + subs->ops.retire = retire_paused_capture_urb; + return 0; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + subs->ops.retire = retire_capture_urb; + return 0; + } + + return -EINVAL; +} + +int snd_usb_substream_prepare(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime) +{ + /* clear urbs (to be sure) */ + deactivate_urbs(subs, 0, 1); + wait_clear_urbs(subs); + + /* for playback, submit the URBs now; otherwise, the first hwptr_done + * updates for all URBs would happen at the same time when starting */ + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { + subs->ops.prepare = prepare_nodata_playback_urb; + return start_urbs(subs, runtime); + } + + return 0; +} + diff --git a/trunk/sound/usb/urb.h b/trunk/sound/usb/urb.h new file mode 100644 index 000000000000..888da38079cf --- /dev/null +++ b/trunk/sound/usb/urb.h @@ -0,0 +1,21 @@ +#ifndef __USBAUDIO_URB_H +#define __USBAUDIO_URB_H + +void snd_usb_init_substream(struct snd_usb_stream *as, + int stream, + struct audioformat *fp); + +int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, + unsigned int period_bytes, + unsigned int rate, + unsigned int frame_bits); + +void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force); + +int snd_usb_substream_prepare(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime); + +int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd); +int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd); + +#endif /* __USBAUDIO_URB_H */ diff --git a/trunk/sound/usb/usbaudio.h b/trunk/sound/usb/usbaudio.h index 3e2b03577936..1e79986b5777 100644 --- a/trunk/sound/usb/usbaudio.h +++ b/trunk/sound/usb/usbaudio.h @@ -80,7 +80,6 @@ enum quirk_type { QUIRK_MIDI_CME, QUIRK_MIDI_AKAI, QUIRK_MIDI_US122L, - QUIRK_MIDI_FTDI, QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UAXX,