diff options
154 files changed, 4369 insertions, 7796 deletions
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl index 598c22f3b3ac..5de23c007078 100644 --- a/Documentation/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -4288,7 +4288,7 @@ struct _snd_pcm_runtime { <![CDATA[ struct snd_rawmidi *rmidi; snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port, info_flags, - irq, irq_flags, &rmidi); + irq, &rmidi); ]]> </programlisting> </informalexample> @@ -4343,6 +4343,13 @@ struct _snd_pcm_runtime { by itself to start processing the output stream in the irq handler. </para> + <para> + If the MPU-401 interface shares its interrupt with the other logical + devices on the card, set <constant>MPU401_INFO_IRQ_HOOK</constant> + (see <link linkend="midi-interface-interrupt-handler"><citetitle> + below</citetitle></link>). + </para> + <para> Usually, the port address corresponds to the command port and port + 1 corresponds to the data port. If not, you may change @@ -4375,14 +4382,12 @@ struct _snd_pcm_runtime { </para> <para> - The 6th argument specifies the irq number for UART. If the irq - is already allocated, pass 0 to the 7th argument - (<parameter>irq_flags</parameter>). Otherwise, pass the flags - for irq allocation - (<constant>SA_XXX</constant> 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. + 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. </para> </section> @@ -4390,12 +4395,13 @@ struct _snd_pcm_runtime { <title>Interrupt Handler</title> <para> When the interrupt is allocated in - <function>snd_mpu401_uart_new()</function>, 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 - <function>snd_mpu401_uart_interrupt()</function> explicitly when - a UART interrupt is invoked and checked in your own interrupt - handler. + <function>snd_mpu401_uart_new()</function>, 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 <constant>MPU401_INFO_IRQ_HOOK</constant>, and call + <function>snd_mpu401_uart_interrupt()</function> explicitly from your + own interrupt handler when it has determined that a UART interrupt + has occurred. </para> <para> diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 89757012c7ff..936699e4f04b 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -886,6 +886,12 @@ 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/Documentation/sound/alsa/HD-Audio-Controls.txt b/Documentation/sound/alsa/HD-Audio-Controls.txt index 1482035243e6..e9621e349e17 100644 --- a/Documentation/sound/alsa/HD-Audio-Controls.txt +++ b/Documentation/sound/alsa/HD-Audio-Controls.txt @@ -98,3 +98,19 @@ 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/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index d70c93bdcadf..4f3443230d89 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -29,9 +29,6 @@ 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) @@ -46,15 +43,10 @@ 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) @@ -66,43 +58,15 @@ ALC262 ALC267/268 ========== - 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) + N/A 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 @@ -111,15 +75,10 @@ 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 ====== - base Base model (ASUS NX90) - auto auto-config reading BIOS (default) + N/A ALC882/883/885/888/889 ====================== @@ -175,28 +134,11 @@ ALC882/883/885/888/889 ALC861/660 ========== - 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) + N/A ALC861VD/660VD ============== - 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) + N/A CMI9880 ======= @@ -289,7 +231,6 @@ 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/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index c82beb007634..03e2771ddeef 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -447,7 +447,10 @@ 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. +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. The `[model]` line allows to change the model name of the each codec. In the example above, it will be changed to model=auto. @@ -491,7 +494,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 @@ -524,6 +527,54 @@ 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/MAINTAINERS b/MAINTAINERS index bbf42cd74e2a..1dbbb278d218 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5991,7 +5991,7 @@ M: Jaroslav Kysela <perex@perex.cz> M: Takashi Iwai <tiwai@suse.de> 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-2.6.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git T: git git://git.alsa-project.org/alsa-kernel.git S: Maintained F: Documentation/sound/ diff --git a/include/linux/input.h b/include/linux/input.h index a637e7814334..a514fb8faea3 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -814,6 +814,7 @@ 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/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index 0fd3fbdd8283..f30253599501 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -377,12 +377,6 @@ struct usb_endpoint_descriptor { #define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ #define USB_ENDPOINT_DIR_MASK 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_XFERTYPE_MASK 0x03 /* in bmAttributes */ #define USB_ENDPOINT_XFER_CONTROL 0 #define USB_ENDPOINT_XFER_ISOC 1 @@ -390,6 +384,17 @@ struct usb_endpoint_descriptor { #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 */ + /*-------------------------------------------------------------------------*/ /** diff --git a/include/sound/asound.h b/include/sound/asound.h index 5d6074faa279..a2e4ff5ba9e9 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -706,7 +706,7 @@ struct snd_timer_tread { * * ****************************************************************************/ -#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7) struct snd_ctl_card_info { int card; /* card number */ @@ -803,6 +803,8 @@ 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/include/sound/initval.h b/include/sound/initval.h index 1daa6dff8297..f99a0d2ddfe7 100644 --- a/include/sound/initval.h +++ b/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_DISABLED | IRQF_PROBE_SHARED, "ALSA Test IRQ", + IRQF_PROBE_SHARED, "ALSA Test IRQ", (void *) irq_table)) { free_irq(*irq_table, (void *) irq_table); return *irq_table; diff --git a/include/sound/jack.h b/include/sound/jack.h index c140fc7cbd3f..63c790742db4 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -42,6 +42,7 @@ 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/include/sound/mpu401.h b/include/sound/mpu401.h index 1f1d53f8830b..20230db00ef1 100644 --- a/include/sound/mpu401.h +++ b/include/sound/mpu401.h @@ -50,7 +50,10 @@ #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 @@ -73,8 +76,7 @@ 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 (-1 = poll) */ - int irq_flags; + int irq; /* IRQ number of MPU-401 chip */ unsigned long mode; /* MPU401_MODE_XXXX */ int timer_invoked; @@ -131,7 +133,6 @@ 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/include/sound/pcm.h b/include/sound/pcm.h index 57e71fa33f7c..3e7fda6e8164 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -825,6 +825,8 @@ 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, @@ -1035,6 +1037,8 @@ 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/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index 3687a6cc9881..762af68c8996 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -1067,7 +1067,6 @@ 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; } @@ -1112,8 +1111,7 @@ static int onyx_i2c_remove(struct i2c_client *client) aoa_codec_unregister(&onyx->codec); of_node_put(onyx->codec.node); - if (onyx->codec_info) - kfree(onyx->codec_info); + kfree(onyx->codec_info); kfree(onyx); return 0; } diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c index 3fd1a7e24928..552b97afbca5 100644 --- a/sound/aoa/fabrics/layout.c +++ b/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/sound/arm/aaci.c b/sound/arm/aaci.c index d0cead38d5fb..e518d38b1c74 100644 --- a/sound/arm/aaci.c +++ b/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 | IRQF_DISABLED, DRIVER_NAME, aaci); + IRQF_SHARED, DRIVER_NAME, aaci); if (ret != 0) aaci->users--; } diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 88eec3847df2..8ad65352bf91 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/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, IRQF_DISABLED, "AC97", NULL); + ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL); if (ret < 0) goto err_irq; diff --git a/sound/core/control.c b/sound/core/control.c index f8c5be464510..978fe1a8e9f0 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -989,7 +989,6 @@ 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, @@ -1001,6 +1000,28 @@ 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) { @@ -1055,11 +1076,46 @@ 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; - if (ue->tlv_data) - kfree(ue->tlv_data); + + kfree(ue->tlv_data); + kfree(ue->priv_data); kfree(ue); } @@ -1072,8 +1128,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, long private_size; struct user_element *ue; int idx, err; - - if (card->user_ctl_count >= MAX_USER_CONTROLS) + + if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS) return -ENOMEM; if (info->count < 1) return -EINVAL; @@ -1101,7 +1157,10 @@ 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; - kctl.info = snd_ctl_elem_user_info; + if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) + kctl.info = snd_ctl_elem_user_enum_info; + else + 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) @@ -1122,6 +1181,11 @@ 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) @@ -1143,9 +1207,17 @@ 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/sound/core/control_compat.c b/sound/core/control_compat.c index 426874429a5e..2bb95a7a8809 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -83,6 +83,8 @@ struct snd_ctl_elem_info32 { u32 items; u32 item; char name[64]; + u64 names_ptr; + u32 names_length; } enumerated; unsigned char reserved[128]; } value; @@ -372,6 +374,8 @@ 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/sound/core/hwdep.c b/sound/core/hwdep.c index a70ee7f1ed98..031e215b6dde 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -272,7 +272,14 @@ static int snd_hwdep_control_ioctl(struct snd_card *card, if (get_user(device, (int __user *)arg)) return -EFAULT; mutex_lock(®ister_mutex); - device = device < 0 ? 0 : device + 1; + + if (device < 0) + device = 0; + else if (device < SNDRV_MINOR_HWDEPS) + device++; + else + device = SNDRV_MINOR_HWDEPS; + while (device < SNDRV_MINOR_HWDEPS) { if (snd_hwdep_search(card, device)) break; diff --git a/sound/core/jack.c b/sound/core/jack.c index 53b53e97c896..240a3e13470d 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -30,6 +30,7 @@ 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/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index d8359cfeca15..1b5e0c49a0ad 100644 --- a/sound/core/oss/mixer_oss.c +++ b/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; - strcpy(id.name, name); + strlcpy(id.name, name, sizeof(id.name)); id.index = index; return snd_ctl_find_id(card, &id); } diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 86d0caf91b35..95d1e789715f 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1399,6 +1399,32 @@ 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) { @@ -1761,6 +1787,10 @@ 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 { @@ -1771,16 +1801,32 @@ 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_interruptible(wait_time); + + tout = schedule_timeout(wait_time); + snd_pcm_stream_lock_irq(substream); + set_current_state(TASK_INTERRUPTIBLE); switch (runtime->status->state) { case SNDRV_PCM_STATE_SUSPENDED: err = -ESTRPIPE; @@ -1806,14 +1852,9 @@ 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/sound/core/pcm_native.c b/sound/core/pcm_native.c index 1c6be91dfb98..77d7df22e7c8 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2058,16 +2058,12 @@ EXPORT_SYMBOL(snd_pcm_open_substream); static int snd_pcm_open_file(struct file *file, struct snd_pcm *pcm, - int stream, - struct snd_pcm_file **rpcm_file) + int stream) { 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; @@ -2083,8 +2079,7 @@ 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; } @@ -2113,7 +2108,6 @@ 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) { @@ -2131,7 +2125,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, &pcm_file); + err = snd_pcm_open_file(file, pcm, stream); if (err >= 0) break; if (err == -EAGAIN) { @@ -3156,8 +3150,8 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { /* * mmap the DMA buffer on RAM */ -static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *area) +int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *area) { area->vm_flags |= VM_RESERVED; #ifdef ARCH_HAS_DMA_MMAP_COHERENT @@ -3177,6 +3171,7 @@ static int snd_pcm_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 @@ -3242,7 +3237,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_default_mmap(substream, area); + err = snd_pcm_lib_default_mmap(substream, area); if (!err) atomic_inc(&substream->mmap_count); return err; diff --git a/sound/core/timer.c b/sound/core/timer.c index 7c1cbf0a0dc4..67ebf1c21c04 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -328,6 +328,8 @@ 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) { @@ -353,6 +355,7 @@ 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); @@ -531,6 +534,8 @@ 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/sound/drivers/aloop.c b/sound/drivers/aloop.c index a0da7755fcea..4067f1548949 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -575,7 +575,8 @@ 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_malloc_pages(substream, params_buffer_bytes(params)); + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(params)); } static int loopback_hw_free(struct snd_pcm_substream *substream) @@ -587,7 +588,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_pages(substream); + return snd_pcm_lib_free_vmalloc_buffer(substream); } static unsigned int get_cable_index(struct snd_pcm_substream *substream) @@ -740,6 +741,8 @@ 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 = { @@ -751,6 +754,8 @@ 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, @@ -771,10 +776,6 @@ 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/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c index 5cfcb908c430..2c7a7636f472 100644 --- a/sound/drivers/ml403-ac97cr.c +++ b/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, IRQF_DISABLED, + if (request_irq(irq, snd_ml403_ac97cr_irq, 0, 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, IRQF_DISABLED, + if (request_irq(irq, snd_ml403_ac97cr_irq, 0, dev_name(&pfdev->dev), (void *)ml403_ac97cr)) { snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " "unable to grab IRQ %d\n", diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index 149d05a8202d..1c02852aceea 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c @@ -86,8 +86,7 @@ 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], irq[dev] >= 0 ? IRQF_DISABLED : 0, - NULL); + irq[dev], NULL); if (err < 0) { printk(KERN_ERR "MPU401 not detected at 0x%lx\n", port[dev]); goto _err; diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 2af09996a3d0..e91698a634b2 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/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. Also, if irq < 0, then + * interrupts thus output is done via polling. Without interrupt, * 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->irq < 0) + if (mpu->info_flags & MPU401_INFO_USE_TIMER) 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->irq < 0) + if (mpu->info_flags & MPU401_INFO_USE_TIMER) 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_flags && mpu->irq >= 0) + if (mpu->irq >= 0) free_irq(mpu->irq, (void *) mpu); release_and_free_resource(mpu->res); kfree(mpu); @@ -509,8 +509,7 @@ 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 irq number, -1 if no interrupt for mpu - * @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved. + * @irq: the ISA irq number, -1 if not to be allocated * @rrawmidi: the pointer to store the new rawmidi instance * * Creates a new MPU-401 instance. @@ -525,7 +524,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_flags, + int irq, struct snd_rawmidi ** rrawmidi) { struct snd_mpu401 *mpu; @@ -577,8 +576,8 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, mpu->cport = port + 2; else mpu->cport = port + 1; - if (irq >= 0 && irq_flags) { - if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags, + if (irq >= 0) { + if (request_irq(irq, snd_mpu401_uart_interrupt, 0, "MPU401 UART", (void *) mpu)) { snd_printk(KERN_ERR "mpu401_uart: " "unable to grab IRQ %d\n", irq); @@ -586,9 +585,10 @@ 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/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 5c426df87678..1eef4ccebe4b 100644 --- a/sound/drivers/mtpav.c +++ b/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, IRQF_DISABLED, "MOTU MTPAV", mcard)) { + if (request_irq(irq, snd_mtpav_irqh, 0, "MOTU MTPAV", mcard)) { snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq); return -EBUSY; } diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index a25fb7b1f441..fc1d822802c3 100644 --- a/sound/drivers/serial-u16550.c +++ b/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, - IRQF_DISABLED, "Serial MIDI", uart)) { + 0, "Serial MIDI", uart)) { snd_printk(KERN_WARNING "irq %d busy. Using Polling.\n", irq); } else { diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 440030818db7..cd094ecaca3b 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -51,7 +51,6 @@ 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/sound/firewire/speakers.c b/sound/firewire/speakers.c index 3fc257da180c..cbe6bb9e53b6 100644 --- a/sound/firewire/speakers.c +++ b/sound/firewire/speakers.c @@ -778,9 +778,10 @@ 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); @@ -796,8 +797,8 @@ static void fwspk_bus_reset(struct fw_unit *unit) fcp_bus_reset(fwspk->unit); if (cmp_connection_update(&fwspk->connection) < 0) { - mutex_lock(&fwspk->mutex); amdtp_out_stream_pcm_abort(&fwspk->stream); + mutex_lock(&fwspk->mutex); fwspk_stop_stream(fwspk); mutex_unlock(&fwspk->mutex); return; diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index 3cb75bc97699..a87a2b566e19 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/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], IRQF_DISABLED, + mpu_port[dev], 0, mpu_irq[dev], NULL) < 0) printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", mpu_port[dev]); } diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 05aef8b97e96..177eed3271bc 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/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, IRQF_DISABLED, "AD1816A", (void *) chip)) { + if (request_irq(irq, snd_ad1816a_interrupt, 0, "AD1816A", (void *) chip)) { snd_printk(KERN_ERR "ad1816a: can't grab IRQ %d\n", irq); snd_ad1816a_free(chip); return -EBUSY; diff --git a/sound/isa/als100.c b/sound/isa/als100.c index 20becc89f6f6..706effd6b3cd 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c @@ -256,7 +256,6 @@ 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/sound/isa/azt2320.c b/sound/isa/azt2320.c index aac8dc15c2fe..b7bdbf307740 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c @@ -234,8 +234,7 @@ 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], IRQF_DISABLED, - NULL) < 0) + mpu_irq[dev], NULL) < 0) snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); } diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index fe79a169acb5..dca69f80305f 100644 --- a/sound/isa/cmi8330.c +++ b/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], - IRQF_DISABLED, NULL) < 0) + NULL) < 0) printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", mpuport[dev]); } diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c index cb9153e75b82..409fa0ad7843 100644 --- a/sound/isa/cs423x/cs4231.c +++ b/sound/isa/cs423x/cs4231.c @@ -131,7 +131,6 @@ 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/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 999dc1e0fdbd..0dbde461e6c1 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -449,8 +449,7 @@ 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], - mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, NULL) < 0) + mpu_irq[dev], NULL) < 0) printk(KERN_WARNING IDENT ": MPU401 not detected\n"); } diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c index 0cde8131a575..5493e9e4bcd5 100644 --- a/sound/isa/es1688/es1688.c +++ b/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], IRQF_DISABLED, NULL); + mpu_irq[n], NULL); if (error < 0) return error; } diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 07676200496a..d3eab6fb0866 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/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, IRQF_DISABLED, "ES1688", (void *) chip)) { + if (request_irq(irq, snd_es1688_interrupt, 0, "ES1688", (void *) chip)) { snd_printk(KERN_ERR "es1688: can't grab IRQ %d\n", irq); return -EBUSY; } diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index fb4d6b34bbca..bf6ad0bf51c6 100644 --- a/sound/isa/es18xx.c +++ b/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, IRQF_DISABLED, "ES18xx", + if (request_irq(irq, snd_es18xx_interrupt, 0, "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], 0, - irq[dev], 0, &chip->rmidi); + mpu_port[dev], MPU401_INFO_IRQ_HOOK, + -1, &chip->rmidi); if (err < 0) return err; } diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c index ee54df082b9c..e51d3244742a 100644 --- a/sound/isa/galaxy/galaxy.c +++ b/sound/isa/galaxy/galaxy.c @@ -585,8 +585,7 @@ 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], - IRQF_DISABLED, NULL); + mpu_port[n], 0, mpu_irq[n], NULL); if (err < 0) goto error; } diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 12eb98f2f931..3167e5ac3699 100644 --- a/sound/isa/gus/gus_main.c +++ b/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, IRQF_DISABLED, "GUS GF1", (void *) gus)) { + if (irq >= 0 && request_irq(irq, snd_gus_interrupt, 0, "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/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index 008e8e5bfa37..c4733c08b60b 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -317,8 +317,7 @@ 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], IRQF_DISABLED, NULL); + es1688->mpu_port, 0, mpu_irq[n], NULL); if (error < 0) goto out; } diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 3e4a58b72913..c43faa057ff6 100644 --- a/sound/isa/gus/gusmax.c +++ b/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, IRQF_DISABLED, "GUS MAX", (void *)maxcard)) { + if (request_irq(xirq, snd_gusmax_interrupt, 0, "GUS MAX", (void *)maxcard)) { snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq); err = -EBUSY; goto _err; diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index c7b80e4730fc..5f869a32b48c 100644 --- a/sound/isa/gus/interwave.c +++ b/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, IRQF_DISABLED, + if (request_irq(xirq, snd_interwave_interrupt, 0, "InterWave", iwcard)) { snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq); return -EBUSY; diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 91d6023a63e5..0961e2cf20ca 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/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], IRQF_DISABLED, + mpu_irq[0], &chip->rmidi); if (err < 0) { printk(KERN_ERR LOGNAME diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 9b915e27b5bd..bbafb0b543ea 100644 --- a/sound/isa/opl3sa2.c +++ b/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, IRQF_DISABLED, + err = request_irq(xirq, snd_opl3sa2_interrupt, 0, "OPL3-SA2", card); if (err) { snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq); @@ -707,8 +707,9 @@ 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], 0, - xirq, 0, &chip->rmidi)) < 0) + midi_port[dev], + MPU401_INFO_IRQ_HOOK, -1, + &chip->rmidi)) < 0) return err; } sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 8c24102d0d93..d94d0f35cb76 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -1377,8 +1377,7 @@ 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, IRQF_DISABLED, - &rmidi); + mpu_port, 0, miro->mpu_irq, &rmidi); if (error < 0) snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", mpu_port); diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index c35dc68930dc..6dbbfa76b440 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/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, - IRQF_DISABLED, DEV_NAME" - WSS", chip); + 0, 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, IRQF_DISABLED, &rmidi); + mpu_port, 0, mpu_irq, &rmidi); if (error) snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", mpu_port); diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c index 8ccbcddf08e1..54e3c2c18060 100644 --- a/sound/isa/sb/jazz16.c +++ b/sound/isa/sb/jazz16.c @@ -322,7 +322,6 @@ 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/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 4d1c5a300ff8..237f8bd7fbe4 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -394,8 +394,9 @@ 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, 0, - xirq, 0, &chip->rmidi)) < 0) + chip->mpu_port, + MPU401_INFO_IRQ_HOOK, -1, + &chip->rmidi)) < 0) return err; chip->rmidi_callback = snd_mpu401_uart_interrupt; } diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index eae6c1c0eff9..d2e19215813e 100644 --- a/sound/isa/sb/sb_common.c +++ b/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 : IRQF_DISABLED, + IRQF_SHARED : 0, "SoundBlaster", (void *) chip)) { snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq); snd_sbdsp_free(chip); diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index 9a8bbf6dd62a..207c161f100c 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c @@ -658,8 +658,7 @@ 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], IRQF_DISABLED, - NULL) < 0) + mpu_irq[dev], NULL) < 0) snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]); } diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index e2d5d2d3ed96..f2379e102b63 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -825,8 +825,7 @@ 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, IRQF_DISABLED, - &rawmidi); + MPU401_INFO_INTEGRATED, irq, &rawmidi); if (err == 0) { struct snd_mpu401 *mpu = rawmidi->private_data; mpu->open_input = mpu401_open; diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index 711670e4a425..87142977335a 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/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, - IRQF_DISABLED, "ICS2115", acard)) { + 0, "ICS2115", acard)) { snd_printk(KERN_ERR "unable to use ICS2115 IRQ %d\n", ics2115_irq[dev]); return -EBUSY; } @@ -449,8 +449,7 @@ 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], IRQF_DISABLED, - NULL); + cs4232_mpu_irq[dev], NULL); if (err < 0) { snd_printk (KERN_ERR "can't allocate CS4232 MPU-401 device\n"); return err; diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 2a42cc377957..7277c5b7df6c 100644 --- a/sound/isa/wss/wss_lib.c +++ b/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, IRQF_DISABLED, + if (request_irq(irq, snd_wss_interrupt, 0, "WSS", (void *) chip)) { snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq); snd_wss_free(chip); diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c index 446cf9748664..7567ebd71913 100644 --- a/sound/mips/au1x00.c +++ b/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, IRQF_DISABLED, + "AC97 TX", au1000_dma_interrupt, 0, 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, IRQF_DISABLED, + "AC97 RX", au1000_dma_interrupt, 0, au1000->stream[CAPTURE])) < 0){ release_dma_lock(flags); return -EBUSY; diff --git a/sound/oss/pas2_pcm.c b/sound/oss/pas2_pcm.c index 8f7d175767a2..6f13ab4afc6b 100644 --- a/sound/oss/pas2_pcm.c +++ b/sound/oss/pas2_pcm.c @@ -63,13 +63,13 @@ static int pcm_set_speed(int arg) if (pcm_channels & 2) { - foo = ((CLOCK_TICK_RATE / 2) + (arg / 2)) / arg; - arg = ((CLOCK_TICK_RATE / 2) + (foo / 2)) / foo; + foo = ((PIT_TICK_RATE / 2) + (arg / 2)) / arg; + arg = ((PIT_TICK_RATE / 2) + (foo / 2)) / foo; } else { - foo = (CLOCK_TICK_RATE + (arg / 2)) / arg; - arg = (CLOCK_TICK_RATE + (foo / 2)) / foo; + foo = (PIT_TICK_RATE + (arg / 2)) / arg; + arg = (PIT_TICK_RATE + (foo / 2)) / foo; } pcm_speed = arg; diff --git a/sound/oss/pss.c b/sound/oss/pss.c index 9b800ce5100e..2fc0624024b5 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -673,7 +673,8 @@ 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 (check_region(pss_cdrom_port, 2)) { + } else if (!request_region(pss_cdrom_port, 2, "PSS CDROM")) { + pss_cdrom_port = -1; printk(KERN_ERR "PSS: CDROM I/O port conflict.\n"); } else { set_io_base(devc, CONF_CDROM, pss_cdrom_port); @@ -1232,7 +1233,8 @@ 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/sound/oss/sound_timer.c b/sound/oss/sound_timer.c index 48cda6c4c257..8021c85f076d 100644 --- a/sound/oss/sound_timer.c +++ b/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 */ - strcpy(sound_timer.info.name, name); + strlcpy(sound_timer.info.name, name, sizeof(sound_timer.info.name)); sound_timer_devs[n] = &sound_timer; } EXPORT_SYMBOL(sound_timer_init); diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 50abf5bf8e09..88168044375f 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -1,5 +1,10 @@ # 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 @@ -563,11 +568,6 @@ 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/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 200c9a1d48b7..a872d0a82976 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1909,6 +1909,7 @@ 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/sound/pci/als4000.c b/sound/pci/als4000.c index a9c1af33f276..04628696eb08 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -931,8 +931,9 @@ 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, - pci->irq, 0, &chip->rmidi)) < 0) { + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &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/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c index 65b7ca13115b..bd47521b24ec 100644 --- a/sound/pci/asihpi/hpicmn.c +++ b/sound/pci/asihpi/hpicmn.c @@ -631,13 +631,12 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, if (!p_cache) return NULL; - p_cache->p_info = - kmalloc(sizeof(*p_cache->p_info) * control_count, GFP_KERNEL); + p_cache->p_info = kzalloc(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/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index 0dc8d259d1ed..e6c6a0febb75 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/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, - 0, 0, 0, &rmidi)) != 0) { + MPU401_INFO_IRQ_HOOK, -1, &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, - 0, 0, &rmidi)) != 0) { + MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO | + MPU401_INFO_IRQ_HOOK, -1, &rmidi)) != 0) { hwwrite(vortex->mmio, VORTEX_CTRL, (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index e4d76a270c9f..d24fe425e87f 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -2625,16 +2625,19 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) int err; snd_azf3328_dbgcallenter(); - if (dev >= SNDRV_CARDS) - return -ENODEV; + if (dev >= SNDRV_CARDS) { + err = -ENODEV; + goto out; + } if (!enable[dev]) { dev++; - return -ENOENT; + err = -ENOENT; + goto out; } err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); if (err < 0) - return err; + goto out; strcpy(card->driver, "AZF3328"); strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); @@ -2649,8 +2652,9 @@ 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, - pci->irq, 0, &chip->rmidi + MPU401_HW_AZT2320, chip->mpu_io, + MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, + -1, &chip->rmidi ); if (err < 0) { snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 9cf99fb7eb9c..da9c73211eca 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -3228,8 +3228,9 @@ 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), - cm->irq, 0, &cm->rmidi)) < 0) { + MPU401_INFO_INTEGRATED : 0) | + MPU401_INFO_IRQ_HOOK, + -1, &cm->rmidi)) < 0) { printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi); } } diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index 457d21189b0d..2c8622617c8c 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/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 : 8; + playback_count = (IEC958 == device) ? 1 : 256; capture_count = (FRONT == device) ? 1 : 0; err = snd_pcm_new(atc->card, "ctxfi", device, playback_count, capture_count, &pcm); diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index c749fa720889..e134b3a5780d 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -20,7 +20,7 @@ #include "cthardware.h" #include <linux/slab.h> -#define SRC_RESOURCE_NUM 64 +#define SRC_RESOURCE_NUM 256 #define SRCIMP_RESOURCE_NUM 256 static unsigned int conj_mask; diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h index b23adfca4de6..e6da60eb19ce 100644 --- a/sound/pci/ctxfi/ctvmem.h +++ b/sound/pci/ctxfi/ctvmem.h @@ -18,7 +18,7 @@ #ifndef CTVMEM_H #define CTVMEM_H -#define CT_PTP_NUM 1 /* num of device page table pages */ +#define CT_PTP_NUM 4 /* num of device page table pages */ #include <linux/mutex.h> #include <linux/list.h> diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 622bace148e3..e22b8e2bbd88 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1146,6 +1146,11 @@ 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/sound/pci/es1938.c b/sound/pci/es1938.c index 26a5a2f25d4b..718a2643474e 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1854,8 +1854,9 @@ 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, - chip->irq, 0, &chip->rmidi) < 0) { + chip->mpu_port, + MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, + -1, &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/sound/pci/es1968.c b/sound/pci/es1968.c index 99ea9320c6b5..407e4abc4356 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2843,8 +2843,9 @@ 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, - chip->irq, 0, &chip->rmidi)) < 0) { + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &chip->rmidi)) < 0) { printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n"); } } diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index f9123f09e83e..136f7232bb7c 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -68,6 +68,7 @@ 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) @@ -728,11 +729,14 @@ 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 = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; + struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); reg &= ~(FM801_GPIO_GP(gpio.data) | FM801_GPIO_GP(gpio.clk) | @@ -750,7 +754,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 = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; + struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); return (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 | (reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0; @@ -760,7 +764,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 = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; + struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); /* use GPIO lines and set write enable bit */ reg |= FM801_GPIO_GS(gpio.data) | @@ -1150,7 +1154,8 @@ static int snd_fm801_free(struct fm801 *chip) __end_hw: #ifdef CONFIG_SND_FM801_TEA575X_BOOL - snd_tea575x_exit(&chip->tea); + if (!(chip->tea575x_tuner & TUNER_DISABLED)) + snd_tea575x_exit(&chip->tea); #endif if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -1236,7 +1241,6 @@ 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) { @@ -1245,17 +1249,19 @@ 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", - snd_fm801_tea575x_gpios[tea575x_tuner - 1].name); + get_tea575x_gpio(chip)->name); break; } } if (tea575x_tuner == 4) { snd_printk(KERN_ERR "TEA575x radio not found\n"); - snd_fm801_free(chip); - return -ENODEV; + chip->tea575x_tuner = TUNER_DISABLED; } } - strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card)); + if (!(chip->tea575x_tuner & TUNER_DISABLED)) { + strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name, + sizeof(chip->tea.card)); + } #endif *rchip = chip; @@ -1306,8 +1312,9 @@ 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, - chip->irq, 0, &chip->rmidi)) < 0) { + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &chip->rmidi)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 87365d5ea2a9..f928d6634723 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -6,6 +6,9 @@ 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/sound/pci/hda/alc260_quirks.c b/sound/pci/hda/alc260_quirks.c index 21ec2cb100b0..3b5170b9700f 100644 --- a/sound/pci/hda/alc260_quirks.c +++ b/sound/pci/hda/alc260_quirks.c @@ -7,9 +7,6 @@ enum { ALC260_AUTO, ALC260_BASIC, - ALC260_HP, - ALC260_HP_DC7600, - ALC260_HP_3013, ALC260_FUJITSU_S702X, ALC260_ACER, ALC260_WILL, @@ -142,8 +139,6 @@ 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 */ @@ -170,145 +165,6 @@ 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. */ @@ -480,106 +336,6 @@ 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. @@ -1093,9 +849,6 @@ 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", @@ -1112,15 +865,6 @@ 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), @@ -1144,54 +888,6 @@ 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/sound/pci/hda/alc262_quirks.c b/sound/pci/hda/alc262_quirks.c index 8d2097d77642..7894b2b5aacf 100644 --- a/sound/pci/hda/alc262_quirks.c +++ b/sound/pci/hda/alc262_quirks.c @@ -10,13 +10,7 @@ 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, @@ -66,164 +60,31 @@ static const struct snd_kcontrol_new alc262_base_mixer[] = { { } /* end */ }; -/* update HP, line and mono-out pins according to the master switch */ -#define alc262_hp_master_update alc260_hp_master_update +/* bind hp and internal speaker mute (with plug check) as master switch */ -static void alc262_hp_bpc_setup(struct hda_codec *codec) +static int alc262_hippo_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; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; + *ucontrol->value.integer.value = !spec->master_mute; + return 0; } -static void alc262_hp_wildwest_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x16; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -#define alc262_hp_master_sw_get alc260_hp_master_sw_get -#define alc262_hp_master_sw_put alc260_hp_master_sw_put - -#define ALC262_HP_MASTER_SWITCH \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Master Playback Switch", \ - .info = snd_ctl_boolean_mono_info, \ - .get = alc262_hp_master_sw_get, \ - .put = alc262_hp_master_sw_put, \ - }, \ - { \ - .iface = NID_MAPPING, \ - .name = "Master Playback Switch", \ - .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \ - } - - -static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { - ALC262_HP_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { - ALC262_HP_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { - HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hp_t5735_setup(struct hda_codec *codec) +static int alc262_hippo_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; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; + if (val == spec->master_mute) + return 0; + spec->master_mute = val; + update_outputs(codec); + return 1; } -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, \ @@ -239,6 +100,9 @@ static const struct hda_input_mux alc262_hp_rp5700_capture_source = { (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), @@ -279,8 +143,7 @@ static void alc262_hippo_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc262_hippo1_setup(struct hda_codec *codec) @@ -289,8 +152,7 @@ static void alc262_hippo1_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } @@ -353,8 +215,7 @@ static void alc262_tyan_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } @@ -496,8 +357,7 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec) spec->ext_mic_pin = 0x18; spec->int_mic_pin = 0x12; spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_PIN); } /* @@ -571,27 +431,6 @@ 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; @@ -599,8 +438,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } /* bind volumes of both NID 0x0c and 0x0d */ @@ -646,8 +484,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { @@ -752,8 +589,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->jack_present = snd_hda_jack_detect(codec, 0x15); - if (spec->jack_present) + spec->hp_jack_present = snd_hda_jack_detect(codec, 0x15); + if (spec->hp_jack_present) mute = HDA_AMP_MUTE; } /* mute/unmute internal speaker */ @@ -817,206 +654,6 @@ 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 */ @@ -1042,13 +679,8 @@ 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", @@ -1061,41 +693,6 @@ 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), @@ -1166,68 +763,6 @@ 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 }, @@ -1238,19 +773,6 @@ 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/sound/pci/hda/alc268_quirks.c b/sound/pci/hda/alc268_quirks.c deleted file mode 100644 index be58bf2f3aec..000000000000 --- a/sound/pci/hda/alc268_quirks.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * ALC267/ALC268 quirk models - * included by patch_realtek.c - */ - -/* ALC268 models */ -enum { - ALC268_AUTO, - ALC267_QUANTA_IL1, - ALC268_3ST, - ALC268_TOSHIBA, - ALC268_ACER, - ALC268_ACER_DMIC, - ALC268_ACER_ASPIRE_ONE, - ALC268_DELL, - ALC268_ZEPTO, -#ifdef CONFIG_SND_DEBUG - ALC268_TEST, -#endif - ALC268_MODEL_LAST /* last tag */ -}; - -/* - * ALC268 channel source setting (2 channel) - */ -#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID -#define alc268_modes alc260_modes - -static const hda_nid_t alc268_dac_nids[2] = { - /* front, hp */ - 0x02, 0x03 -}; - -static const hda_nid_t alc268_adc_nids[2] = { - /* ADC0-1 */ - 0x08, 0x07 -}; - -static const hda_nid_t alc268_adc_nids_alt[1] = { - /* ADC0 */ - 0x08 -}; - -static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 }; - -static const struct snd_kcontrol_new alc268_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc268_toshiba_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc268_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* Toshiba specific */ -static const struct hda_verb alc268_toshiba_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - -/* Acer specific */ -/* bind volumes of both NID 0x02 and 0x03 */ -static const struct hda_bind_ctls alc268_acer_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static void alc268_acer_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -#define alc268_acer_master_sw_get alc262_hp_master_sw_get -#define alc268_acer_master_sw_put alc262_hp_master_sw_put - -static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x15, - .info = snd_ctl_boolean_mono_info, - .get = alc268_acer_master_sw_get, - .put = alc268_acer_master_sw_put, - }, - HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc268_acer_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, - .info = snd_ctl_boolean_mono_info, - .get = alc268_acer_master_sw_get, - .put = alc268_acer_master_sw_put, - }, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, - .info = snd_ctl_boolean_mono_info, - .get = alc268_acer_master_sw_get, - .put = alc268_acer_master_sw_put, - }, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc268_acer_aspire_one_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x23, AC_VERB_SET_CONNECT_SEL, 0x06}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017}, - { } -}; - -static const struct hda_verb alc268_acer_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - { } -}; - -/* unsolicited event for HP jack sensing */ -#define alc268_toshiba_setup alc262_hippo_setup - -static void alc268_acer_lc_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -static const struct snd_kcontrol_new alc268_dell_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc268_dell_verbs[] = { - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - { } -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc268_dell_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct hda_verb alc267_quanta_il1_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - { } -}; - -static void alc267_quanta_il1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; -} - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc268_base_init_verbs[] = { - /* Unmute DAC0-1 and set vol = 0 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* set PCBEEP vol = 0, mute connections */ - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Unmute Selector 23h,24h and set the default input to mic-in */ - - {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - { } -}; - -/* only for model=test */ -#ifdef CONFIG_SND_DEBUG -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc268_volume_init_verbs[] = { - /* set output DAC */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - { } -}; -#endif /* CONFIG_SND_DEBUG */ - -static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), - _DEFINE_CAPSRC(1), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc268_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT), - _DEFINE_CAPSRC(2), - { } /* end */ -}; - -static const struct hda_input_mux alc268_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x3 }, - }, -}; - -static const struct hda_input_mux alc268_acer_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux alc268_acer_dmic_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x6 }, - { "Line", 0x2 }, - }, -}; - -#ifdef CONFIG_SND_DEBUG -static const struct snd_kcontrol_new alc268_test_mixer[] = { - /* Volume widgets */ - HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT), - HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT), - HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT), - HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT), - HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT), - /* The below appears problematic on some hardwares */ - /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/ - HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT), - - /* Controls for GPIO pins, assuming they are configured as outputs */ - ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), - ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), - ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), - ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), - - /* Switches to allow the digital SPDIF output pin to be enabled. - * The ALC268 does not have an SPDIF input. - */ - ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01), - - /* A switch allowing EAPD to be enabled. Some laptops seem to use - * this output to turn on an external amplifier. - */ - ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), - ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), - - { } /* end */ -}; -#endif - -/* - * configuration and preset - */ -static const char * const alc268_models[ALC268_MODEL_LAST] = { - [ALC267_QUANTA_IL1] = "quanta-il1", - [ALC268_3ST] = "3stack", - [ALC268_TOSHIBA] = "toshiba", - [ALC268_ACER] = "acer", - [ALC268_ACER_DMIC] = "acer-dmic", - [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", - [ALC268_DELL] = "dell", - [ALC268_ZEPTO] = "zepto", -#ifdef CONFIG_SND_DEBUG - [ALC268_TEST] = "test", -#endif - [ALC268_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc268_cfg_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER), - SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", - ALC268_ACER_ASPIRE_ONE), - SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), - SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO), - SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0, - "Dell Inspiron Mini9/Vostro A90", ALC268_DELL), - /* almost compatible with toshiba but with optional digital outs; - * auto-probing seems working fine - */ - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series", - ALC268_AUTO), - SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), - SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), - SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), - SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), - {} -}; - -/* Toshiba laptops have no unique PCI SSID but only codec SSID */ -static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { - SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO), - SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO), - SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", - ALC268_TOSHIBA), - {} -}; - -static const struct alc_config_preset alc268_presets[] = { - [ALC267_QUANTA_IL1] = { - .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer, - alc268_capture_nosrc_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc267_quanta_il1_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc267_quanta_il1_setup, - .init_hook = alc_inithook, - }, - [ALC268_3ST] = { - .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC268_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - }, - [ALC268_TOSHIBA] = { - .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_toshiba_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_toshiba_setup, - .init_hook = alc_inithook, - }, - [ALC268_ACER] = { - .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_acer_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_acer_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_acer_setup, - .init_hook = alc_inithook, - }, - [ALC268_ACER_DMIC] = { - .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_acer_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_acer_dmic_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_acer_setup, - .init_hook = alc_inithook, - }, - [ALC268_ACER_ASPIRE_ONE] = { - .mixers = { alc268_acer_aspire_one_mixer, - alc268_beep_mixer, - alc268_capture_nosrc_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_acer_aspire_one_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_acer_lc_setup, - .init_hook = alc_inithook, - }, - [ALC268_DELL] = { - .mixers = { alc268_dell_mixer, alc268_beep_mixer, - alc268_capture_nosrc_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_dell_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_dell_setup, - .init_hook = alc_inithook, - }, - [ALC268_ZEPTO] = { - .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_toshiba_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC268_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc268_toshiba_setup, - .init_hook = alc_inithook, - }, -#ifdef CONFIG_SND_DEBUG - [ALC268_TEST] = { - .mixers = { alc268_test_mixer, alc268_capture_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_volume_init_verbs, - alc268_beep_init_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC268_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, - }, -#endif -}; - diff --git a/sound/pci/hda/alc269_quirks.c b/sound/pci/hda/alc269_quirks.c deleted file mode 100644 index 14fdcf29b154..000000000000 --- a/sound/pci/hda/alc269_quirks.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - * ALC269/ALC270/ALC275/ALC276 quirk models - * included by patch_realtek.c - */ - -/* ALC269 models */ -enum { - ALC269_AUTO, - ALC269_BASIC, - ALC269_QUANTA_FL1, - ALC269_AMIC, - ALC269_DMIC, - ALC269VB_AMIC, - ALC269VB_DMIC, - ALC269_FUJITSU, - ALC269_LIFEBOOK, - ALC271_ACER, - ALC269_MODEL_LAST /* last tag */ -}; - -/* - * ALC269 channel source setting (2 channel) - */ -#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID - -#define alc269_dac_nids alc260_dac_nids - -static const hda_nid_t alc269_adc_nids[1] = { - /* ADC1 */ - 0x08, -}; - -static const hda_nid_t alc269_capsrc_nids[1] = { - 0x23, -}; - -static const hda_nid_t alc269vb_adc_nids[1] = { - /* ADC1 */ - 0x09, -}; - -static const hda_nid_t alc269vb_capsrc_nids[1] = { - 0x22, -}; - -#define alc269_modes alc260_modes -#define alc269_capture_source alc880_lg_lw_capture_source - -static const struct snd_kcontrol_new alc269_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc269_lifebook_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT), - { } -}; - -static const struct snd_kcontrol_new alc269_laptop_mixer[] = { - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = { - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269_asus_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* capture mixer elements */ -static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -/* FSC amilo */ -#define alc269_fujitsu_mixer alc269_laptop_mixer - -static const struct hda_verb alc269_quanta_fl1_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - { } -}; - -static const struct hda_verb alc269_lifebook_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) -{ - alc_hp_automute(codec); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x680); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x480); -} - -#define alc269_lifebook_speaker_automute \ - alc269_quanta_fl1_speaker_automute - -static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) -{ - unsigned int present_laptop; - unsigned int present_dock; - - present_laptop = snd_hda_jack_detect(codec, 0x18); - present_dock = snd_hda_jack_detect(codec, 0x1b); - - /* Laptop mic port overrides dock mic port, design decision */ - if (present_dock) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x3); - if (present_laptop) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x0); - if (!present_dock && !present_laptop) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x1); -} - -static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC_HP_EVENT: - alc269_quanta_fl1_speaker_automute(codec); - break; - case ALC_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -static void alc269_lifebook_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc269_lifebook_speaker_automute(codec); - if ((res >> 26) == ALC_MIC_EVENT) - alc269_lifebook_mic_autoswitch(codec); -} - -static void alc269_quanta_fl1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) -{ - alc269_quanta_fl1_speaker_automute(codec); - alc_mic_automute(codec); -} - -static void alc269_lifebook_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.hp_pins[1] = 0x1a; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; -} - -static void alc269_lifebook_init_hook(struct hda_codec *codec) -{ - alc269_lifebook_speaker_automute(codec); - alc269_lifebook_mic_autoswitch(codec); -} - -static const struct hda_verb alc269_laptop_dmic_init_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc269_laptop_amic_init_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x06}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = { - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc271_acer_dmic_verbs[] = { - {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, - {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x22, AC_VERB_SET_CONNECT_SEL, 6}, - { } -}; - -static void alc269_laptop_amic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc269_laptop_dmic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -static void alc269vb_laptop_amic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc269_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* - * Set up output mixers (0x02 - 0x03) - */ - /* set vol=0 to output mixers */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* FIXME: use Mux-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* set EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc269vb_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* - * Set up output mixers (0x02 - 0x03) - */ - /* set vol=0 to output mixers */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* FIXME: use Mux-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x22, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* set EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -/* - * configuration and preset - */ -static const char * const alc269_models[ALC269_MODEL_LAST] = { - [ALC269_BASIC] = "basic", - [ALC269_QUANTA_FL1] = "quanta", - [ALC269_AMIC] = "laptop-amic", - [ALC269_DMIC] = "laptop-dmic", - [ALC269_FUJITSU] = "fujitsu", - [ALC269_LIFEBOOK] = "lifebook", - [ALC269_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc269_cfg_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), - SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER), - SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", - ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC), - SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", - ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", - ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC), - SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC), - SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO), - SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), - SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC), - SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), - SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC), - SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC), - SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC), - {} -}; - -static const struct alc_config_preset alc269_presets[] = { - [ALC269_BASIC] = { - .mixers = { alc269_base_mixer }, - .init_verbs = { alc269_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - }, - [ALC269_QUANTA_FL1] = { - .mixers = { alc269_quanta_fl1_mixer }, - .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - .unsol_event = alc269_quanta_fl1_unsol_event, - .setup = alc269_quanta_fl1_setup, - .init_hook = alc269_quanta_fl1_init_hook, - }, - [ALC269_AMIC] = { - .mixers = { alc269_laptop_mixer }, - .cap_mixer = alc269_laptop_analog_capture_mixer, - .init_verbs = { alc269_init_verbs, - alc269_laptop_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269_laptop_amic_setup, - .init_hook = alc_inithook, - }, - [ALC269_DMIC] = { - .mixers = { alc269_laptop_mixer }, - .cap_mixer = alc269_laptop_digital_capture_mixer, - .init_verbs = { alc269_init_verbs, - alc269_laptop_dmic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269_laptop_dmic_setup, - .init_hook = alc_inithook, - }, - [ALC269VB_AMIC] = { - .mixers = { alc269vb_laptop_mixer }, - .cap_mixer = alc269vb_laptop_analog_capture_mixer, - .init_verbs = { alc269vb_init_verbs, - alc269vb_laptop_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269vb_laptop_amic_setup, - .init_hook = alc_inithook, - }, - [ALC269VB_DMIC] = { - .mixers = { alc269vb_laptop_mixer }, - .cap_mixer = alc269vb_laptop_digital_capture_mixer, - .init_verbs = { alc269vb_init_verbs, - alc269vb_laptop_dmic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269vb_laptop_dmic_setup, - .init_hook = alc_inithook, - }, - [ALC269_FUJITSU] = { - .mixers = { alc269_fujitsu_mixer }, - .cap_mixer = alc269_laptop_digital_capture_mixer, - .init_verbs = { alc269_init_verbs, - alc269_laptop_dmic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc269_laptop_dmic_setup, - .init_hook = alc_inithook, - }, - [ALC269_LIFEBOOK] = { - .mixers = { alc269_lifebook_mixer }, - .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - .unsol_event = alc269_lifebook_unsol_event, - .setup = alc269_lifebook_setup, - .init_hook = alc269_lifebook_init_hook, - }, - [ALC271_ACER] = { - .mixers = { alc269_asus_mixer }, - .cap_mixer = alc269vb_laptop_digital_capture_mixer, - .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .adc_nids = alc262_dmic_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids), - .capsrc_nids = alc262_dmic_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - .dig_out_nid = ALC880_DIGOUT_NID, - .unsol_event = alc_sku_unsol_event, - .setup = alc269vb_laptop_dmic_setup, - .init_hook = alc_inithook, - }, -}; - diff --git a/sound/pci/hda/alc662_quirks.c b/sound/pci/hda/alc662_quirks.c deleted file mode 100644 index e69a6ea3083a..000000000000 --- a/sound/pci/hda/alc662_quirks.c +++ /dev/null @@ -1,1408 +0,0 @@ -/* - * ALC662/ALC663/ALC665/ALC670 quirk models - * included by patch_realtek.c - */ - -/* ALC662 models */ -enum { - ALC662_AUTO, - ALC662_3ST_2ch_DIG, - ALC662_3ST_6ch_DIG, - ALC662_3ST_6ch, - ALC662_5ST_DIG, - ALC662_LENOVO_101E, - ALC662_ASUS_EEEPC_P701, - ALC662_ASUS_EEEPC_EP20, - ALC663_ASUS_M51VA, - ALC663_ASUS_G71V, - ALC663_ASUS_H13, - ALC663_ASUS_G50V, - ALC662_ECS, - ALC663_ASUS_MODE1, - ALC662_ASUS_MODE2, - ALC663_ASUS_MODE3, - ALC663_ASUS_MODE4, - ALC663_ASUS_MODE5, - ALC663_ASUS_MODE6, - ALC663_ASUS_MODE7, - ALC663_ASUS_MODE8, - ALC272_DELL, - ALC272_DELL_ZM1, - ALC272_SAMSUNG_NC10, - ALC662_MODEL_LAST, -}; - -#define ALC662_DIGOUT_NID 0x06 -#define ALC662_DIGIN_NID 0x0a - -static const hda_nid_t alc662_dac_nids[3] = { - /* front, rear, clfe */ - 0x02, 0x03, 0x04 -}; - -static const hda_nid_t alc272_dac_nids[2] = { - 0x02, 0x03 -}; - -static const hda_nid_t alc662_adc_nids[2] = { - /* ADC1-2 */ - 0x09, 0x08 -}; - -static const hda_nid_t alc272_adc_nids[1] = { - /* ADC1-2 */ - 0x08, -}; - -static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; -static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; - - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ -static const struct hda_input_mux alc662_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc662_lenovo_101e_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static const struct hda_input_mux alc663_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -#if 0 /* set to 1 for testing other input sources below */ -static const struct hda_input_mux alc272_nc10_capture_source = { - .num_items = 16, - .items = { - { "Autoselect Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "In-0x02", 0x2 }, - { "In-0x03", 0x3 }, - { "In-0x04", 0x4 }, - { "In-0x05", 0x5 }, - { "In-0x06", 0x6 }, - { "In-0x07", 0x7 }, - { "In-0x08", 0x8 }, - { "In-0x09", 0x9 }, - { "In-0x0a", 0x0a }, - { "In-0x0b", 0x0b }, - { "In-0x0c", 0x0c }, - { "In-0x0d", 0x0d }, - { "In-0x0e", 0x0e }, - { "In-0x0f", 0x0f }, - }, -}; -#endif - -/* - * 2ch mode - */ -static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc662_3ST_ch2_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc662_3ST_ch6_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = { - { 2, alc662_3ST_ch2_init }, - { 6, alc662_3ST_ch6_init }, -}; - -/* - * 2ch mode - */ -static const struct hda_verb alc662_sixstack_ch6_init[] = { - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc662_sixstack_ch8_init[] = { - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static const struct hda_channel_mode alc662_5stack_modes[2] = { - { 2, alc662_sixstack_ch6_init }, - { 6, alc662_sixstack_ch8_init }, -}; - -/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 - * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b - */ - -static const struct snd_kcontrol_new alc662_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - /*Input mixer control */ - HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc663_asus_one_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_m51va_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_tree_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_four_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc662_1bjd_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc663_asus_two_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", - &alc663_asus_two_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_g71v_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_g50v_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc663_mode7_mixer[] = { - HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), - HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), - HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc663_mode8_mixer[] = { - HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), - HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), - HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), - HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - - -static const struct snd_kcontrol_new alc662_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static const struct hda_verb alc662_init_verbs[] = { - /* ADC: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Rear Pin: output 1 (0x0d) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - { } -}; - -static const struct hda_verb alc662_eapd_init_verbs[] = { - /* always trun on EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc662_sue_init_verbs[] = { - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_FRONT_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc662_eeepc_sue_init_verbs[] = { - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* Set Unsolicited Event*/ -static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_m51va_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_21jd_amic_init_verbs[] = { - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc662_1bjd_amic_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_15jd_amic_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_g71v_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ - /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ - - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_FRONT_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_g50v_init_verbs[] = { - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc662_ecs_init_verbs[] = { - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc272_dell_zm1_init_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc272_dell_init_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_mode7_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct hda_verb alc663_mode8_init_verbs[] = { - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { } /* end */ -}; - -static void alc662_lenovo_101e_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.line_out_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->detect_line = 1; - spec->automute_lines = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc662_eeepc_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - alc262_hippo1_setup(codec); - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -static void alc662_eeepc_ep20_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc663_m51va_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -/* ***************** Mode1 ******************************/ -static void alc663_mode1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode2 ******************************/ -static void alc662_mode2_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode3 ******************************/ -static void alc663_mode3_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode4 ******************************/ -static void alc663_mode4_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute_mixer_nid[1] = 0x0e; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode5 ******************************/ -static void alc663_mode5_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute_mixer_nid[1] = 0x0e; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode6 ******************************/ -static void alc663_mode6_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute_mixer_nid[0] = 0x0c; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_MIXER; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode7 ******************************/ -static void alc663_mode7_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x19; - spec->auto_mic = 1; -} - -/* ***************** Mode8 ******************************/ -static void alc663_mode8_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.hp_pins[1] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_PIN; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -static void alc663_g71v_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x21; - spec->autocfg.line_out_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; - spec->detect_line = 1; - spec->automute_lines = 1; - spec->ext_mic_pin = 0x18; - spec->int_mic_pin = 0x12; - spec->auto_mic = 1; -} - -#define alc663_g50v_setup alc663_m51va_setup - -static const struct snd_kcontrol_new alc662_ecs_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - - HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc272_nc10_mixer[] = { - /* Master Playback automatically created from Speaker and Headphone */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - - -/* - * configuration and preset - */ -static const char * const alc662_models[ALC662_MODEL_LAST] = { - [ALC662_3ST_2ch_DIG] = "3stack-dig", - [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", - [ALC662_3ST_6ch] = "3stack-6ch", - [ALC662_5ST_DIG] = "5stack-dig", - [ALC662_LENOVO_101E] = "lenovo-101e", - [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", - [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", - [ALC662_ECS] = "ecs", - [ALC663_ASUS_M51VA] = "m51va", - [ALC663_ASUS_G71V] = "g71v", - [ALC663_ASUS_H13] = "h13", - [ALC663_ASUS_G50V] = "g50v", - [ALC663_ASUS_MODE1] = "asus-mode1", - [ALC662_ASUS_MODE2] = "asus-mode2", - [ALC663_ASUS_MODE3] = "asus-mode3", - [ALC663_ASUS_MODE4] = "asus-mode4", - [ALC663_ASUS_MODE5] = "asus-mode5", - [ALC663_ASUS_MODE6] = "asus-mode6", - [ALC663_ASUS_MODE7] = "asus-mode7", - [ALC663_ASUS_MODE8] = "asus-mode8", - [ALC272_DELL] = "dell", - [ALC272_DELL_ZM1] = "dell-zm1", - [ALC272_SAMSUNG_NC10] = "samsung-nc10", - [ALC662_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc662_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), - SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL), - SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), - SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7), - SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7), - SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8), - SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5), - SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6), - SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), - /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/ - SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3), - SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V), - /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/ - SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2), - SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1), - SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4), - SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), - SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), - SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), - SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", - ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO), - SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", - ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13), - SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), - SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0", - ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x", - ALC663_ASUS_H13), - SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E), - {} -}; - -static const struct alc_config_preset alc662_presets[] = { - [ALC662_3ST_2ch_DIG] = { - .mixers = { alc662_3ST_2ch_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_capture_source, - }, - [ALC662_3ST_6ch_DIG] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc662_capture_source, - }, - [ALC662_3ST_6ch] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc662_capture_source, - }, - [ALC662_5ST_DIG] = { - .mixers = { alc662_base_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes), - .channel_mode = alc662_5stack_modes, - .input_mux = &alc662_capture_source, - }, - [ALC662_LENOVO_101E] = { - .mixers = { alc662_lenovo_101e_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_sue_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_lenovo_101e_setup, - .init_hook = alc_inithook, - }, - [ALC662_ASUS_EEEPC_P701] = { - .mixers = { alc662_eeepc_p701_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_eeepc_sue_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_eeepc_setup, - .init_hook = alc_inithook, - }, - [ALC662_ASUS_EEEPC_EP20] = { - .mixers = { alc662_eeepc_ep20_mixer, - alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_eeepc_ep20_sue_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_eeepc_ep20_setup, - .init_hook = alc_inithook, - }, - [ALC662_ECS] = { - .mixers = { alc662_ecs_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_ecs_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_eeepc_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_M51VA] = { - .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_m51va_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_m51va_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_G71V] = { - .mixers = { alc663_g71v_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_g71v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_g71v_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_H13] = { - .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_m51va_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .setup = alc663_m51va_setup, - .unsol_event = alc_sku_unsol_event, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_G50V] = { - .mixers = { alc663_g50v_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_g50v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .input_mux = &alc663_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_g50v_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE1] = { - .mixers = { alc663_m51va_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_21jd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode1_setup, - .init_hook = alc_inithook, - }, - [ALC662_ASUS_MODE2] = { - .mixers = { alc662_1bjd_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc662_1bjd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc662_mode2_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE3] = { - .mixers = { alc663_two_hp_m1_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_two_hp_amic_m1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode3_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE4] = { - .mixers = { alc663_asus_21jd_clfe_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_21jd_amic_init_verbs}, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode4_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE5] = { - .mixers = { alc663_asus_15jd_clfe_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_15jd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode5_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE6] = { - .mixers = { alc663_two_hp_m2_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_two_hp_amic_m2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode6_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE7] = { - .mixers = { alc663_mode7_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_mode7_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode7_setup, - .init_hook = alc_inithook, - }, - [ALC663_ASUS_MODE8] = { - .mixers = { alc663_mode8_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_mode8_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .hp_nid = 0x03, - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode8_setup, - .init_hook = alc_inithook, - }, - [ALC272_DELL] = { - .mixers = { alc663_m51va_mixer }, - .cap_mixer = alc272_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc272_dell_init_verbs }, - .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc272_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .adc_nids = alc272_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), - .capsrc_nids = alc272_capsrc_nids, - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_m51va_setup, - .init_hook = alc_inithook, - }, - [ALC272_DELL_ZM1] = { - .mixers = { alc663_m51va_mixer }, - .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc272_dell_zm1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc272_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .adc_nids = alc662_adc_nids, - .num_adc_nids = 1, - .capsrc_nids = alc662_capsrc_nids, - .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc663_m51va_setup, - .init_hook = alc_inithook, - }, - [ALC272_SAMSUNG_NC10] = { - .mixers = { alc272_nc10_mixer }, - .init_verbs = { alc662_init_verbs, - alc662_eapd_init_verbs, - alc663_21jd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc272_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - /*.input_mux = &alc272_nc10_capture_source,*/ - .unsol_event = alc_sku_unsol_event, - .setup = alc663_mode4_setup, - .init_hook = alc_inithook, - }, -}; - - diff --git a/sound/pci/hda/alc680_quirks.c b/sound/pci/hda/alc680_quirks.c deleted file mode 100644 index 0eeb227c7bc2..000000000000 --- a/sound/pci/hda/alc680_quirks.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * ALC680 quirk models - * included by patch_realtek.c - */ - -/* ALC680 models */ -enum { - ALC680_AUTO, - ALC680_BASE, - ALC680_MODEL_LAST, -}; - -#define ALC680_DIGIN_NID ALC880_DIGIN_NID -#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID -#define alc680_modes alc260_modes - -static const hda_nid_t alc680_dac_nids[3] = { - /* Lout1, Lout2, hp */ - 0x02, 0x03, 0x04 -}; - -static const hda_nid_t alc680_adc_nids[3] = { - /* ADC0-2 */ - /* DMIC, MIC, Line-in*/ - 0x07, 0x08, 0x09 -}; - -/* - * Analog capture ADC cgange - */ -static hda_nid_t alc680_get_cur_adc(struct hda_codec *codec) -{ - static hda_nid_t pins[] = {0x18, 0x19}; - static hda_nid_t adcs[] = {0x08, 0x09}; - int i; - - for (i = 0; i < ARRAY_SIZE(pins); i++) { - if (!is_jack_detectable(codec, pins[i])) - continue; - if (snd_hda_jack_detect(codec, pins[i])) - return adcs[i]; - } - return 0x07; -} - -static void alc680_rec_autoswitch(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid = alc680_get_cur_adc(codec); - if (spec->cur_adc && nid != spec->cur_adc) { - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = nid; - snd_hda_codec_setup_stream(codec, nid, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } -} - -static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid = alc680_get_cur_adc(codec); - - spec->cur_adc = nid; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); - return 0; -} - -static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; -} - -static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = { - .substreams = 1, /* can be overridden */ - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .prepare = alc680_capture_pcm_prepare, - .cleanup = alc680_capture_pcm_cleanup - }, -}; - -static const struct snd_kcontrol_new alc680_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT), - { } -}; - -static const struct hda_bind_ctls alc680_bind_cap_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), - 0 - }, -}; - -static const struct hda_bind_ctls alc680_bind_cap_switch = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new alc680_master_capture_mixer[] = { - HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), - HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), - { } /* end */ -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc680_init_verbs[] = { - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, - - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc680_base_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x16; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.num_inputs = 2; - spec->autocfg.inputs[0].pin = 0x18; - spec->autocfg.inputs[0].type = AUTO_PIN_MIC; - spec->autocfg.inputs[1].pin = 0x19; - spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc680_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc_hp_automute(codec); - if ((res >> 26) == ALC_MIC_EVENT) - alc680_rec_autoswitch(codec); -} - -static void alc680_inithook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc680_rec_autoswitch(codec); -} - -/* - * configuration and preset - */ -static const char * const alc680_models[ALC680_MODEL_LAST] = { - [ALC680_BASE] = "base", - [ALC680_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc680_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), - {} -}; - -static const struct alc_config_preset alc680_presets[] = { - [ALC680_BASE] = { - .mixers = { alc680_base_mixer }, - .cap_mixer = alc680_master_capture_mixer, - .init_verbs = { alc680_init_verbs }, - .num_dacs = ARRAY_SIZE(alc680_dac_nids), - .dac_nids = alc680_dac_nids, - .dig_out_nid = ALC680_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc680_modes), - .channel_mode = alc680_modes, - .unsol_event = alc680_unsol_event, - .setup = alc680_base_setup, - .init_hook = alc680_inithook, - - }, -}; diff --git a/sound/pci/hda/alc861_quirks.c b/sound/pci/hda/alc861_quirks.c deleted file mode 100644 index d719ec6350eb..000000000000 --- a/sound/pci/hda/alc861_quirks.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - * ALC660/ALC861 quirk models - * included by patch_realtek.c - */ - -/* ALC861 models */ -enum { - ALC861_AUTO, - ALC861_3ST, - ALC660_3ST, - ALC861_3ST_DIG, - ALC861_6ST_DIG, - ALC861_UNIWILL_M31, - ALC861_TOSHIBA, - ALC861_ASUS, - ALC861_ASUS_LAPTOP, - ALC861_MODEL_LAST, -}; - -/* - * ALC861 channel source setting (2/6 channel selection for 3-stack) - */ - -/* - * set the path ways for 2 channel output - * need to set the codec line out and mic 1 pin widgets to inputs - */ -static const struct hda_verb alc861_threestack_ch2_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* set pin widget 18h (mic1/2) for input, for mic also enable - * the vref - */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ -#endif - { } /* end */ -}; -/* - * 6ch mode - * need to set the codec line out and mic 1 pin widgets to outputs - */ -static const struct hda_verb alc861_threestack_ch6_init[] = { - /* set pin widget 1Ah (line in) for output (Back Surround)*/ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* set pin widget 18h (mic1) for output (CLFE)*/ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - - { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ -#endif - { } /* end */ -}; - -static const struct hda_channel_mode alc861_threestack_modes[2] = { - { 2, alc861_threestack_ch2_init }, - { 6, alc861_threestack_ch6_init }, -}; -/* Set mic1 as input and unmute the mixer */ -static const struct hda_verb alc861_uniwill_m31_ch2_init[] = { - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { } /* end */ -}; -/* Set mic1 as output and mute mixer */ -static const struct hda_verb alc861_uniwill_m31_ch4_init[] = { - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { } /* end */ -}; - -static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = { - { 2, alc861_uniwill_m31_ch2_init }, - { 4, alc861_uniwill_m31_ch4_init }, -}; - -/* Set mic1 and line-in as input and unmute the mixer */ -static const struct hda_verb alc861_asus_ch2_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* set pin widget 18h (mic1/2) for input, for mic also enable - * the vref - */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ -#endif - { } /* end */ -}; -/* Set mic1 nad line-in as output and mute mixer */ -static const struct hda_verb alc861_asus_ch6_init[] = { - /* set pin widget 1Ah (line in) for output (Back Surround)*/ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ - /* set pin widget 18h (mic1) for output (CLFE)*/ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ - { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ -#endif - { } /* end */ -}; - -static const struct hda_channel_mode alc861_asus_modes[2] = { - { 2, alc861_asus_ch2_init }, - { 6, alc861_asus_ch6_init }, -}; - -/* patch-ALC861 */ - -static const struct snd_kcontrol_new alc861_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), - - /*Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_3ST_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ - - /* Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_threestack_modes), - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_toshiba_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ - - /* Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes), - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861_asus_mixer[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), - - /* Input mixer control */ - HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_asus_modes), - }, - { } -}; - -/* additional mixer */ -static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - { } -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc861_base_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - - { } -}; - -static const struct hda_verb alc861_threestack_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -static const struct hda_verb alc861_uniwill_m31_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - /* this has to be set to VREF80 */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -static const struct hda_verb alc861_asus_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) - * according to codec#0 this is the HP jack - */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */ - /* route front PCM to HP */ - { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - /* this has to be set to VREF80 */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -/* additional init verbs for ASUS laptops */ -static const struct hda_verb alc861_asus_laptop_init_verbs[] = { - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */ - { } -}; - -static const struct hda_verb alc861_toshiba_init_verbs[] = { - {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc861_toshiba_automute(struct hda_codec *codec) -{ - unsigned int present = snd_hda_jack_detect(codec, 0x0f); - - snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, - HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); -} - -static void alc861_toshiba_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc861_toshiba_automute(codec); -} - -#define ALC861_DIGOUT_NID 0x07 - -static const struct hda_channel_mode alc861_8ch_modes[1] = { - { 8, NULL } -}; - -static const hda_nid_t alc861_dac_nids[4] = { - /* front, surround, clfe, side */ - 0x03, 0x06, 0x05, 0x04 -}; - -static const hda_nid_t alc660_dac_nids[3] = { - /* front, clfe, surround */ - 0x03, 0x05, 0x06 -}; - -static const hda_nid_t alc861_adc_nids[1] = { - /* ADC0-2 */ - 0x08, -}; - -static const struct hda_input_mux alc861_capture_source = { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x1 }, - { "CD", 0x4 }, - { "Mixer", 0x5 }, - }, -}; - -/* - * configuration and preset - */ -static const char * const alc861_models[ALC861_MODEL_LAST] = { - [ALC861_3ST] = "3stack", - [ALC660_3ST] = "3stack-660", - [ALC861_3ST_DIG] = "3stack-dig", - [ALC861_6ST_DIG] = "6stack-dig", - [ALC861_UNIWILL_M31] = "uniwill-m31", - [ALC861_TOSHIBA] = "toshiba", - [ALC861_ASUS] = "asus", - [ALC861_ASUS_LAPTOP] = "asus-laptop", - [ALC861_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc861_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), - SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), - SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG), - SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), - /* FIXME: the entry below breaks Toshiba A100 (model=auto works!) - * Any other models that need this preset? - */ - /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */ - SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST), - SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST), - SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), - SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), - SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP), - /* FIXME: the below seems conflict */ - /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */ - SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), - SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), - {} -}; - -static const struct alc_config_preset alc861_presets[] = { - [ALC861_3ST] = { - .mixers = { alc861_3ST_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_3ST_DIG] = { - .mixers = { alc861_base_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_6ST_DIG] = { - .mixers = { alc861_base_mixer }, - .init_verbs = { alc861_base_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes), - .channel_mode = alc861_8ch_modes, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC660_3ST] = { - .mixers = { alc861_3ST_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660_dac_nids), - .dac_nids = alc660_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_UNIWILL_M31] = { - .mixers = { alc861_uniwill_m31_mixer }, - .init_verbs = { alc861_uniwill_m31_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes), - .channel_mode = alc861_uniwill_m31_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_TOSHIBA] = { - .mixers = { alc861_toshiba_mixer }, - .init_verbs = { alc861_base_init_verbs, - alc861_toshiba_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - .unsol_event = alc861_toshiba_unsol_event, - .init_hook = alc861_toshiba_automute, - }, - [ALC861_ASUS] = { - .mixers = { alc861_asus_mixer }, - .init_verbs = { alc861_asus_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_asus_modes), - .channel_mode = alc861_asus_modes, - .need_dac_fix = 1, - .hp_nid = 0x06, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_ASUS_LAPTOP] = { - .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer }, - .init_verbs = { alc861_asus_init_verbs, - alc861_asus_laptop_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, -}; - diff --git a/sound/pci/hda/alc861vd_quirks.c b/sound/pci/hda/alc861vd_quirks.c deleted file mode 100644 index 8f28450f41f8..000000000000 --- a/sound/pci/hda/alc861vd_quirks.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * ALC660-VD/ALC861-VD quirk models - * included by patch_realtek.c - */ - -/* ALC861-VD models */ -enum { - ALC861VD_AUTO, - ALC660VD_3ST, - ALC660VD_3ST_DIG, - ALC660VD_ASUS_V1S, - ALC861VD_3ST, - ALC861VD_3ST_DIG, - ALC861VD_6ST_DIG, - ALC861VD_LENOVO, - ALC861VD_DALLAS, - ALC861VD_HP, - ALC861VD_MODEL_LAST, -}; - -#define ALC861VD_DIGOUT_NID 0x06 - -static const hda_nid_t alc861vd_dac_nids[4] = { - /* front, surr, clfe, side surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -/* dac_nids for ALC660vd are in a different order - according to - * Realtek's driver. - * This should probably result in a different mixer for 6stack models - * of ALC660vd codecs, but for now there is only 3stack mixer - * - and it is the same as in 861vd. - * adc_nids in ALC660vd are (is) the same as in 861vd - */ -static const hda_nid_t alc660vd_dac_nids[3] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x04, 0x03 -}; - -static const hda_nid_t alc861vd_adc_nids[1] = { - /* ADC0 */ - 0x09, -}; - -static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 }; - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ -static const struct hda_input_mux alc861vd_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc861vd_dallas_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - }, -}; - -static const struct hda_input_mux alc861vd_hp_capture_source = { - .num_items = 2, - .items = { - { "Front Mic", 0x0 }, - { "ATAPI Mic", 0x1 }, - }, -}; - -/* - * 2ch mode - */ -static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 6ch mode - */ -static const struct hda_verb alc861vd_6stack_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static const struct hda_verb alc861vd_6stack_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static const struct hda_channel_mode alc861vd_6stack_modes[2] = { - { 6, alc861vd_6stack_ch6_init }, - { 8, alc861vd_6stack_ch8_init }, -}; - -static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 - * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b - */ -static const struct snd_kcontrol_new alc861vd_6st_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861vd_3st_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - { } /* end */ -}; - -static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/ - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - { } /* end */ -}; - -/* Pin assignment: Speaker=0x14, HP = 0x15, - * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d - */ -static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -/* Pin assignment: Speaker=0x14, Line-out = 0x15, - * Front Mic=0x18, ATAPI Mic = 0x19, - */ -static const struct snd_kcontrol_new alc861vd_hp_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - { } /* end */ -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc861vd_volume_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of - * the analog-loopback mixer widget - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x02 - 0x05) - */ - /* set vol=0 to output mixers */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - { } -}; - -/* - * 3-stack pin configuration: - * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b - */ -static const struct hda_verb alc861vd_3stack_init_verbs[] = { - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 6-stack pin configuration: - */ -static const struct hda_verb alc861vd_6stack_init_verbs[] = { - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Rear Pin: output 1 (0x0d) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -static const struct hda_verb alc861vd_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - -static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - {} -}; - -static void alc861vd_lenovo_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -static void alc861vd_lenovo_init_hook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc88x_simple_mic_automute(codec); -} - -static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC_MIC_EVENT: - alc88x_simple_mic_automute(codec); - break; - default: - alc_sku_unsol_event(codec, res); - break; - } -} - -static const struct hda_verb alc861vd_dallas_verbs[] = { - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - - { } /* end */ -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc861vd_dallas_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; -} - -/* - * configuration and preset - */ -static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = { - [ALC660VD_3ST] = "3stack-660", - [ALC660VD_3ST_DIG] = "3stack-660-digout", - [ALC660VD_ASUS_V1S] = "asus-v1s", - [ALC861VD_3ST] = "3stack", - [ALC861VD_3ST_DIG] = "3stack-digout", - [ALC861VD_6ST_DIG] = "6stack-digout", - [ALC861VD_LENOVO] = "lenovo", - [ALC861VD_DALLAS] = "dallas", - [ALC861VD_HP] = "hp", - [ALC861VD_AUTO] = "auto", -}; - -static const struct snd_pci_quirk alc861vd_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), - SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), - SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), - /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */ - SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S), - SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), - SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), - SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), - /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ - SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS), - SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), - SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), - {} -}; - -static const struct alc_config_preset alc861vd_presets[] = { - [ALC660VD_3ST] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC660VD_3ST_DIG] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_3ST] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_3ST_DIG] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_6ST_DIG] = { - .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes), - .channel_mode = alc861vd_6stack_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_LENOVO] = { - .mixers = { alc861vd_lenovo_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs, - alc861vd_eapd_verbs, - alc861vd_lenovo_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - .unsol_event = alc861vd_lenovo_unsol_event, - .setup = alc861vd_lenovo_setup, - .init_hook = alc861vd_lenovo_init_hook, - }, - [ALC861VD_DALLAS] = { - .mixers = { alc861vd_dallas_mixer }, - .init_verbs = { alc861vd_dallas_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_dallas_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc861vd_dallas_setup, - .init_hook = alc_hp_automute, - }, - [ALC861VD_HP] = { - .mixers = { alc861vd_hp_mixer }, - .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_hp_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc861vd_dallas_setup, - .init_hook = alc_hp_automute, - }, - [ALC660VD_ASUS_V1S] = { - .mixers = { alc861vd_lenovo_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs, - alc861vd_eapd_verbs, - alc861vd_lenovo_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - .unsol_event = alc861vd_lenovo_unsol_event, - .setup = alc861vd_lenovo_setup, - .init_hook = alc861vd_lenovo_init_hook, - }, -}; - diff --git a/sound/pci/hda/alc880_quirks.c b/sound/pci/hda/alc880_quirks.c index c844d2b59988..bea22edcfd8c 100644 --- a/sound/pci/hda/alc880_quirks.c +++ b/sound/pci/hda/alc880_quirks.c @@ -749,8 +749,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc880_uniwill_init_hook(struct hda_codec *codec) @@ -781,8 +780,7 @@ static void alc880_uniwill_p53_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -1051,8 +1049,7 @@ static void alc880_lg_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x17; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } /* @@ -1137,8 +1134,7 @@ static void alc880_lg_lw_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = { @@ -1188,7 +1184,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->jack_present) + if (spec->hp_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); @@ -1210,8 +1206,7 @@ static void alc880_medion_rim_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } #ifdef CONFIG_SND_HDA_POWER_SAVE diff --git a/sound/pci/hda/alc882_quirks.c b/sound/pci/hda/alc882_quirks.c index 617d04723b82..e251514a26a4 100644 --- a/sound/pci/hda/alc882_quirks.c +++ b/sound/pci/hda/alc882_quirks.c @@ -173,8 +173,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc889_intel_init_hook(struct hda_codec *codec) @@ -191,8 +190,7 @@ 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 */ - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } /* @@ -475,8 +473,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) @@ -487,8 +484,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) @@ -499,8 +495,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) @@ -511,8 +506,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } #define ALC882_DIGOUT_NID 0x06 @@ -1711,8 +1705,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } #define alc885_mb5_setup alc885_imac24_setup @@ -1721,12 +1714,11 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } @@ -1737,8 +1729,7 @@ static void alc885_mbp3_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc885_imac91_setup(struct hda_codec *codec) @@ -1748,8 +1739,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static const struct hda_verb alc882_targa_verbs[] = { @@ -1773,7 +1763,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->jack_present ? 1 : 3); + spec->hp_jack_present ? 1 : 3); } static void alc882_targa_setup(struct hda_codec *codec) @@ -1782,8 +1772,7 @@ static void alc882_targa_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) @@ -2187,8 +2176,7 @@ static void alc883_medion_wim2160_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1a; spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { @@ -2341,8 +2329,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static const struct hda_verb alc883_mitac_verbs[] = { @@ -2507,8 +2494,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static const struct hda_verb alc888_3st_hp_verbs[] = { @@ -2568,8 +2554,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } /* toggle speaker-output according to the hp-jack state */ @@ -2579,8 +2564,7 @@ static void alc883_lenovo_nb0763_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } /* toggle speaker-output according to the hp-jack state */ @@ -2593,8 +2577,7 @@ static void alc883_clevo_m720_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc883_clevo_m720_init_hook(struct hda_codec *codec) @@ -2623,8 +2606,7 @@ static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc883_haier_w66_setup(struct hda_codec *codec) @@ -2633,8 +2615,7 @@ static void alc883_haier_w66_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc883_lenovo_101e_setup(struct hda_codec *codec) @@ -2644,10 +2625,7 @@ 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; - spec->automute = 1; - spec->detect_line = 1; - spec->automute_lines = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } /* toggle speaker-output according to the hp-jack state */ @@ -2658,8 +2636,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static const struct hda_verb alc883_acer_eapd_verbs[] = { @@ -2689,8 +2666,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc888_lenovo_sky_setup(struct hda_codec *codec) @@ -2703,8 +2679,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static void alc883_vaiott_setup(struct hda_codec *codec) @@ -2714,8 +2689,7 @@ 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; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static const struct hda_verb alc888_asus_m90v_verbs[] = { @@ -2739,8 +2713,7 @@ static void alc883_mode2_setup(struct hda_codec *codec) spec->ext_mic_pin = 0x18; spec->int_mic_pin = 0x19; spec->auto_mic = 1; - spec->automute = 1; - spec->automute_mode = ALC_AUTOMUTE_AMP; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); } static const struct hda_verb alc888_asus_eee1601_verbs[] = { diff --git a/sound/pci/hda/alc_quirks.c b/sound/pci/hda/alc_quirks.c index 2be1129cf458..a18952ed4311 100644 --- a/sound/pci/hda/alc_quirks.c +++ b/sound/pci/hda/alc_quirks.c @@ -453,6 +453,19 @@ 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/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3e7850c238c3..1715e8b24ff0 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -34,6 +34,9 @@ #include "hda_beep.h" #include <sound/hda_hwdep.h> +#define CREATE_TRACE_POINTS +#include "hda_trace.h" + /* * vendor / preset table */ @@ -208,15 +211,19 @@ 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; @@ -579,9 +586,13 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, return -1; } recursive++; - for (i = 0; i < nums; i++) + 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; if (snd_hda_get_conn_index(codec, conn[i], nid, recursive) >= 0) return i; + } return -1; } EXPORT_SYMBOL_HDA(snd_hda_get_conn_index); @@ -603,6 +614,7 @@ 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; @@ -1479,8 +1491,11 @@ static void really_cleanup_stream(struct hda_codec *codec, struct hda_cvt_setup *q) { hda_nid_t nid = q->nid; - 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); + 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 +); memset(q, 0, sizeof(*q)); q->nid = nid; } @@ -1685,6 +1700,29 @@ 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 * @nid: the pin NID to sense @@ -4083,6 +4121,7 @@ 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); @@ -4121,6 +4160,7 @@ 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; @@ -4533,6 +4573,11 @@ 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, @@ -4565,6 +4610,10 @@ 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, @@ -4645,6 +4694,27 @@ 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 * @@ -4662,12 +4732,13 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. */ -int snd_hda_parse_pin_def_config(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - const hda_nid_t *ignore_nids) +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) { hda_nid_t nid, end_nid; - short seq, assoc_line_out, assoc_speaker; + short seq, assoc_line_out; 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)]; @@ -4678,7 +4749,7 @@ int snd_hda_parse_pin_def_config(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 = assoc_speaker = 0; + assoc_line_out = 0; end_nid = codec->start_nid + codec->num_nodes; for (nid = codec->start_nid; nid < end_nid; nid++) { @@ -4730,16 +4801,10 @@ int snd_hda_parse_pin_def_config(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] = seq; + sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; cfg->speaker_outs++; break; case AC_JACK_HP_OUT: @@ -4788,7 +4853,8 @@ int snd_hda_parse_pin_def_config(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) { + if (!cfg->line_outs && cfg->hp_outs > 1 && + !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) { int i = 0; while (i < cfg->hp_outs) { /* The real HPs should have the sequence 0x0f */ @@ -4825,7 +4891,8 @@ int snd_hda_parse_pin_def_config(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) { + if (!cfg->line_outs && + !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) { if (cfg->speaker_outs) { cfg->line_outs = cfg->speaker_outs; memcpy(cfg->line_out_pins, cfg->speaker_pins, @@ -4843,21 +4910,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, } } - /* 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; - } + 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); sort_autocfg_input_pins(cfg); @@ -4895,7 +4950,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, return 0; } -EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config); +EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg); int snd_hda_get_input_pin_attr(unsigned int def_conf) { @@ -5154,30 +5209,6 @@ 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 * @buf: the string buffer to write @@ -5218,6 +5249,8 @@ 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/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 28ce17d09c33..1c8ddf547a2d 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -144,25 +144,17 @@ static int cea_sampling_frequencies[8] = { SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ }; -static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid, +static unsigned int hdmi_get_eld_data(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 - - 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; + return val; } #define GRAB_BITS(buf, byte, lowbit, bits) \ @@ -326,6 +318,11 @@ 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; @@ -335,24 +332,59 @@ 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 > PAGE_SIZE) { + if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); return -ERANGE; } - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - for (i = 0; i < size; i++) - buf[i] = hdmi_get_eld_byte(codec, nid, i); + /* 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; + } ret = hdmi_update_eld(eld, buf, size); - kfree(buf); +error: 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]; @@ -361,7 +393,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) if (!a->format) return; - snd_print_pcm_rates(a->rates, buf, sizeof(buf)); + hdmi_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); @@ -420,7 +452,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); - snd_print_pcm_rates(a->rates, buf, sizeof(buf)); + hdmi_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/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index bf3ced51e0f8..7e7d0788ddcf 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/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) { - unsigned int vendorid, subid, caddr; + 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 (codec->vendor_id == vendorid && - codec->subsystem_id == subid && + if ((vendorid <= 0 || codec->vendor_id == vendorid) && + (subid <= 0 || codec->subsystem_id == subid) && codec->addr == caddr) { *codecp = codec; break; @@ -756,8 +756,6 @@ 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/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index be6982289c0d..bd7fc99af187 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -34,7 +34,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/kernel.h> @@ -46,6 +45,12 @@ #include <linux/pci.h> #include <linux/mutex.h> #include <linux/reboot.h> +#include <linux/io.h> +#ifdef CONFIG_X86 +/* for snoop control */ +#include <asm/pgtable.h> +#include <asm/cacheflush.h> +#endif #include <sound/core.h> #include <sound/initval.h> #include "hda_codec.h" @@ -116,6 +121,22 @@ 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}," @@ -360,7 +381,7 @@ struct azx_dev { */ unsigned char stream_tag; /* assigned stream */ unsigned char index; /* stream index */ - int device; /* last device number assigned to */ + int assigned_key; /* last device# key assigned to */ unsigned int opened :1; unsigned int running :1; @@ -371,6 +392,7 @@ struct azx_dev { * when link position is not greater than FIFO size */ unsigned int insufficient :1; + unsigned int wc_marked:1; }; /* CORB/RIRB */ @@ -438,6 +460,7 @@ 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]; @@ -481,6 +504,7 @@ 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 \ @@ -542,6 +566,45 @@ 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); /* @@ -563,6 +626,7 @@ 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; } @@ -1079,7 +1143,15 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg, static void azx_init_pci(struct azx *chip) { - unsigned short snoop; + /* 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"); + } + } /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) * TCSEL == Traffic Class Select Register, which sets PCI express QOS @@ -1096,15 +1168,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 "Enabling ATI snoop\n"); + snd_printdd(SFX "Setting ATI snoop: %d\n", azx_snoop(chip)); update_pci_byte(chip->pci, - ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - 0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP); + ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07, + azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0); } /* For NVIDIA HDA, enable snoop */ if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) { - snd_printdd(SFX "Enabling Nvidia snoop\n"); + snd_printdd(SFX "Setting Nvidia snoop: %d\n", azx_snoop(chip)); update_pci_byte(chip->pci, NVIDIA_HDA_TRANSREG_ADDR, 0x0f, NVIDIA_HDA_ENABLE_COHBITS); @@ -1118,16 +1190,20 @@ 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 (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { - pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, - snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP)); + 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); pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); - snd_printdd(SFX "HDA snoop disabled, enabling ... %s\n", - (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) - ? "Failed" : "OK"); } + snd_printdd(SFX "SCH snoop: %s\n", + (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) + ? "Disabled" : "Enabled"); } } @@ -1334,12 +1410,16 @@ 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 */ - 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)); + 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); /* program the length of samples in cyclic buffer */ azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize); @@ -1533,6 +1613,9 @@ 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; @@ -1544,12 +1627,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->device == substream->pcm->device) + if (res->assigned_key == key) break; } if (res) { res->opened = 1; - res->device = substream->pcm->device; + res->assigned_key = key; } return res; } @@ -1599,6 +1682,7 @@ 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); @@ -1613,10 +1697,25 @@ 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, - 128); + buff_step); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - 128); + buff_step); snd_hda_power_up(apcm->codec); err = hinfo->ops.open(hinfo, apcm->codec, substream); if (err < 0) { @@ -1671,19 +1770,30 @@ 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; - return snd_pcm_lib_malloc_pages(substream, + ret = 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 */ @@ -1696,6 +1806,7 @@ 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); } @@ -1924,7 +2035,8 @@ static unsigned int azx_via_get_position(struct azx *chip, } static unsigned int azx_get_position(struct azx *chip, - struct azx_dev *azx_dev) + struct azx_dev *azx_dev, + bool with_check) { unsigned int pos; int stream = azx_dev->substream->stream; @@ -1940,7 +2052,7 @@ static unsigned int azx_get_position(struct azx *chip, default: /* use the position buffer */ pos = le32_to_cpu(*azx_dev->posbuf); - if (chip->position_fix[stream] == POS_FIX_AUTO) { + if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) { if (!pos || pos == (u32)-1) { printk(KERN_WARNING "hda-intel: Invalid position buffer, " @@ -1964,7 +2076,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)); + azx_get_position(chip, azx_dev, false)); } /* @@ -1987,7 +2099,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); + pos = azx_get_position(chip, azx_dev, true); if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) @@ -2054,6 +2166,20 @@ 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, @@ -2063,6 +2189,7 @@ 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, }; @@ -2343,13 +2470,19 @@ 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) + if (chip->azx_dev[i].bdl.area) { + mark_pages_wc(chip, &chip->azx_dev[i].bdl, false); snd_dma_free_pages(&chip->azx_dev[i].bdl); + } } - if (chip->rb.area) + if (chip->rb.area) { + mark_pages_wc(chip, &chip->rb, false); snd_dma_free_pages(&chip->rb); - if (chip->posbuf.area) + } + if (chip->posbuf.area) { + mark_pages_wc(chip, &chip->posbuf, false); snd_dma_free_pages(&chip->posbuf); + } pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip->azx_dev); @@ -2369,6 +2502,7 @@ 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), @@ -2544,6 +2678,7 @@ 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) { @@ -2616,6 +2751,10 @@ 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)); @@ -2667,6 +2806,7 @@ 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, @@ -2676,6 +2816,7 @@ 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) @@ -2817,37 +2958,49 @@ 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 }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | + AZX_DCAPS_BUFSIZE }, /* PBG */ { PCI_DEVICE(0x8086, 0x1d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | + AZX_DCAPS_BUFSIZE}, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | + AZX_DCAPS_BUFSIZE}, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | + AZX_DCAPS_BUFSIZE}, { PCI_DEVICE(0x8086, 0x2668), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH6 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH6 */ { PCI_DEVICE(0x8086, 0x27d8), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH7 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH7 */ { PCI_DEVICE(0x8086, 0x269a), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ESB2 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ESB2 */ { PCI_DEVICE(0x8086, 0x284b), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH8 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH8 */ { PCI_DEVICE(0x8086, 0x293e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH9 */ { PCI_DEVICE(0x8086, 0x293f), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH9 */ { PCI_DEVICE(0x8086, 0x3a3e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH10 */ { PCI_DEVICE(0x8086, 0x3a6e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* 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 }, + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_BUFSIZE }, /* ATI SB 450/600/700/800/900 */ { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 2e7ac31afa8d..79f49e2e8cbc 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -267,11 +267,14 @@ 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 extra_out_nid[3]; /* optional DACs, 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 dig_out_nid; /* digital out audio widget */ const hda_nid_t *slave_dig_outs; int max_channels; /* currently supported analog channels */ @@ -333,9 +336,6 @@ 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 5 +#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS #define AUTO_CFG_MAX_INS 8 struct auto_pin_cfg_item { @@ -442,10 +442,21 @@ 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_def_config(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - const hda_nid_t *ignore_nids); +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) /* amp values */ #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) @@ -492,12 +503,16 @@ 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); } @@ -589,7 +604,8 @@ 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(kc) (((kc)->private_value >> 18) & 0x1) +#define get_amp_direction_(pv) (((pv) >> 18) & 0x1) +#define get_amp_direction(kc) get_amp_direction_((kc)->private_value) #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) @@ -607,6 +623,7 @@ struct cea_sad { }; #define ELD_FIXED_BYTES 20 +#define ELD_MAX_SIZE 256 #define ELD_MAX_MNL 16 #define ELD_MAX_SAD 16 @@ -631,6 +648,7 @@ 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/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 2be57b051aa2..2c981b55940b 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -152,12 +152,18 @@ static void print_amp_vals(struct snd_info_buffer *buffer, static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) { - char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + static unsigned int rates[] = { + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, + 96000, 176400, 192000, 384000 + }; + int i; pcm &= AC_SUPPCM_RATES; snd_iprintf(buffer, " rates [0x%x]:", pcm); - snd_print_pcm_rates(pcm, buf, sizeof(buf)); - snd_iprintf(buffer, "%s\n", buf); + for (i = 0; i < ARRAY_SIZE(rates); i++) + if (pcm & (1 << i)) + snd_iprintf(buffer, " %d", rates[i]); + snd_iprintf(buffer, "\n"); } static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) diff --git a/sound/pci/hda/hda_trace.h b/sound/pci/hda/hda_trace.h new file mode 100644 index 000000000000..9884871ddb00 --- /dev/null +++ b/sound/pci/hda/hda_trace.h @@ -0,0 +1,117 @@ +#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 <linux/tracepoint.h> + +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 <trace/define_trace.h> diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 8648917acffb..d8aac588f23b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -48,6 +48,8 @@ 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; @@ -302,6 +304,72 @@ 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 */ @@ -310,8 +378,15 @@ static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + int err; + set_stream_active(codec, true); + err = 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, @@ -333,11 +408,41 @@ 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, - /* NID is set in ad198x_build_pcms */ + .ops = { + .open = ad1988_alt_playback_pcm_open, + .close = ad1988_alt_playback_pcm_close + }, }; /* @@ -402,7 +507,6 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } - /* */ static const struct hda_pcm_stream ad198x_pcm_analog_playback = { @@ -413,7 +517,8 @@ 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 + .cleanup = ad198x_playback_pcm_cleanup, + .close = ad198x_playback_pcm_close }, }; @@ -2058,7 +2163,6 @@ 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, @@ -2168,6 +2272,17 @@ 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), @@ -2188,6 +2303,7 @@ 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), @@ -2210,13 +2326,6 @@ 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 */ }; @@ -2238,6 +2347,7 @@ 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), @@ -2272,6 +2382,7 @@ 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), @@ -2446,7 +2557,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, 0x01}, /* DAC1:04h */ + {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ {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}, @@ -2594,7 +2705,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, 0x01}, /* DAC1:04h */ + {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ {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}, @@ -2669,7 +2780,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, 0x01}, /* DAC1:04h */ + {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ {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}, @@ -2782,11 +2893,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 */ - 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a + 0x03, 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 */ - 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06 + 0x03, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06 }; if (is_rev2(codec)) return idx_to_dac_rev2[idx]; @@ -3023,8 +3134,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 04 */ - snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01); + case 0x11: /* port-A - DAC 03 */ + snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x00); break; case 0x14: /* port-B - DAC 06 */ snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02); @@ -3150,7 +3261,6 @@ 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", @@ -3208,10 +3318,11 @@ 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)) @@ -3227,19 +3338,7 @@ 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_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)) { + if (board_config == AD1988_6STACK_DIG) { spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; spec->dig_in_nid = AD1988_SPDIF_IN; } @@ -3282,6 +3381,15 @@ 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/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 47d6ffc9b5b5..c45f3e69bcf0 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/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; + int i, idx; hda_nid_t nid; nid = codec->start_nid; @@ -384,9 +384,11 @@ 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; - *idxp = snd_hda_get_conn_index(codec, nid, pin, false); - if (*idxp >= 0) + idx = snd_hda_get_conn_index(codec, nid, pin, false); + if (idx >= 0) { + *idxp = idx; return nid; + } } return 0; } @@ -533,7 +535,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[32]; + char tmp[44]; struct snd_kcontrol_new knew = HDA_CODEC_VOLUME_IDX(tmp, index, 0, 0, HDA_OUTPUT); knew.private_value = pval; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 502fc9499453..0c8b5a1993ed 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -136,6 +136,8 @@ 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; @@ -1867,39 +1869,6 @@ 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}, @@ -1968,7 +1937,6 @@ 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 */ @@ -1980,7 +1948,6 @@ 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", @@ -1995,7 +1962,6 @@ 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), {} }; @@ -2053,13 +2019,6 @@ 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; @@ -3110,6 +3069,7 @@ 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), @@ -3348,6 +3308,8 @@ 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) { @@ -3370,16 +3332,26 @@ 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 type) + struct pin_dac_pair *filled, int nums, + int type) { - int i, nums; + int i, start = nums; - nums = 0; - for (i = 0; i < num_pins; i++) { + for (i = 0; i < num_pins; i++, nums++) { filled[nums].pin = pins[i]; filled[nums].type = type; filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest); - nums++; + 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]); } return nums; } @@ -3395,19 +3367,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, - 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, 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); 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) + if (!dac || (dac & DAC_SLAVE_FLAG)) continue; switch (spec->dac_info[i].type) { case AUTO_PIN_LINE_OUT: @@ -3460,12 +3432,14 @@ 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); - cx_auto_turn_eapd(codec, num_pins, pins, on); + if (spec->pin_eapd_ctrls) + cx_auto_turn_eapd(codec, num_pins, pins, on); } static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) @@ -3490,9 +3464,12 @@ static void cx_auto_update_speakers(struct hda_codec *codec) int on = 1; /* turn on HP EAPD when HP jacks are present */ - if (spec->auto_mute) - on = spec->hp_present; - cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); + 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); + } + /* mute speakers in auto-mode if HP or LO jacks are plugged */ if (spec->auto_mute) on = !(spec->hp_present || @@ -3862,7 +3839,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 && !spec->auto_mic) { + if (imux->num_items > 1) { for (i = 1; i < imux->num_items; i++) { if (spec->imux_info[i].adc != spec->imux_info[0].adc) { spec->adc_switching = 1; @@ -3919,20 +3896,10 @@ static void cx_auto_parse_beep(struct hda_codec *codec) #define cx_auto_parse_beep(codec) #endif -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return true; - return false; -} - -/* parse extra-EAPD that aren't assigned to any pins */ +/* parse EAPDs */ 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; @@ -3941,14 +3908,18 @@ 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) @@ -4035,6 +4006,8 @@ 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) { @@ -4052,8 +4025,9 @@ static void cx_auto_init_output(struct hda_codec *codec) } } cx_auto_update_speakers(codec); - /* turn on/off extra EAPDs, too */ - cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); + /* 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); } static void cx_auto_init_input(struct hda_codec *codec) @@ -4167,9 +4141,11 @@ 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; - caps = query_amp_caps(codec, dac, HDA_OUTPUT); - if (caps & AC_AMPCAP_NUM_STEPS) - return cx_auto_add_pb_volume(codec, dac, name, idx); + 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, pin, HDA_OUTPUT); if (caps & AC_AMPCAP_NUM_STEPS) return cx_auto_add_pb_volume(codec, pin, name, idx); @@ -4191,8 +4167,7 @@ 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; - if (!spec->dac_info[i].dac) - continue; + hda_nid_t dac = spec->dac_info[i].dac; type = spec->dac_info[i].type; if (type == AUTO_PIN_LINE_OUT) type = spec->autocfg.line_out_type; @@ -4211,7 +4186,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) idx = num_spk++; break; } - err = try_add_pb_volume(codec, spec->dac_info[i].dac, + err = try_add_pb_volume(codec, dac, spec->dac_info[i].pin, label, idx); if (err < 0) @@ -4239,6 +4214,8 @@ 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); } @@ -4279,14 +4256,21 @@ 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, err, cidx; + int i, j, 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); - input_conn[i] = (spec->imux_info[i].adc << 8) | cidx; + if (cidx < 0) + continue; + input_conn[i] = spec->imux_info[i].adc; + if (!spec->single_adc_amp) + input_conn[i] |= cidx << 8; if (i > 0 && input_conn[i] != input_conn[0]) multi_connection = 1; } @@ -4315,6 +4299,15 @@ 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); } @@ -4378,6 +4371,53 @@ 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; @@ -4391,6 +4431,15 @@ 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/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 19cb72db9c38..aac3bfacda3f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -324,6 +324,66 @@ 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) @@ -946,7 +1006,6 @@ 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); @@ -963,23 +1022,15 @@ 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; } @@ -1162,6 +1213,25 @@ 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; @@ -1170,12 +1240,25 @@ 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; @@ -1491,7 +1574,7 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { int chs; - unsigned int dataDCC1, dataDCC2, channel_id; + unsigned int dataDCC2, channel_id; int i; struct hdmi_spec *spec = codec->spec; struct hda_spdif_out *spdif = @@ -1501,7 +1584,6 @@ 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/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e125c60fe352..80d6add8a620 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -116,6 +116,8 @@ 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; @@ -159,23 +161,27 @@ 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 jack_present: 1; + unsigned int hp_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: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 */ + 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 */ /* 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; @@ -193,6 +199,7 @@ 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; @@ -202,6 +209,9 @@ 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 */ @@ -525,8 +535,8 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, } } -/* Toggle internal speakers muting */ -static void update_speakers(struct hda_codec *codec) +/* Toggle outputs muting */ +static void update_outputs(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int on; @@ -538,10 +548,10 @@ static void update_speakers(struct hda_codec *codec) do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), spec->autocfg.hp_pins, spec->master_mute, true); - if (!spec->automute) + if (!spec->automute_speaker) on = 0; else - on = spec->jack_present | spec->line_jack_present; + on = spec->hp_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); @@ -551,26 +561,35 @@ static void update_speakers(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_lines || !spec->automute) + if (!spec->automute_lo) on = 0; else - on = spec->jack_present; + on = spec->hp_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; - if (!spec->automute) - return; - spec->jack_present = + spec->hp_jack_present = detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), spec->autocfg.hp_pins); - update_speakers(codec); + if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) + return; + call_update_outputs(codec); } /* standard line-out-automute helper */ @@ -578,12 +597,16 @@ static void alc_line_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - if (!spec->automute || !spec->detect_line) + /* check LO jack only when it's different from HP */ + if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) return; + spec->line_jack_present = detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), spec->autocfg.line_out_pins); - update_speakers(codec); + if (!spec->automute_speaker || !spec->detect_lo) + return; + call_update_outputs(codec); } #define get_connection_index(codec, mux, nid) \ @@ -781,7 +804,7 @@ static int alc_automute_mode_info(struct snd_kcontrol *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - if (spec->automute_hp_lo) { + if (spec->automute_speaker_possible && spec->automute_lo_possible) { uinfo->value.enumerated.items = 3; texts = texts3; } else { @@ -800,13 +823,12 @@ 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; - if (!spec->automute) - val = 0; - else if (!spec->automute_lines) - val = 1; - else - val = 2; + unsigned int val = 0; + if (spec->automute_speaker) + val++; + if (spec->automute_lo) + val++; + ucontrol->value.enumerated.item[0] = val; return 0; } @@ -819,28 +841,36 @@ static int alc_automute_mode_put(struct snd_kcontrol *kcontrol, switch (ucontrol->value.enumerated.item[0]) { case 0: - if (!spec->automute) + if (!spec->automute_speaker && !spec->automute_lo) return 0; - spec->automute = 0; + spec->automute_speaker = 0; + spec->automute_lo = 0; break; case 1: - if (spec->automute && !spec->automute_lines) - return 0; - spec->automute = 1; - spec->automute_lines = 0; + 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; break; case 2: - if (!spec->automute_hp_lo) + if (!spec->automute_lo_possible || !spec->automute_speaker_possible) return -EINVAL; - if (spec->automute && spec->automute_lines) + if (spec->automute_speaker && spec->automute_lo) return 0; - spec->automute = 1; - spec->automute_lines = 1; + spec->automute_speaker = 1; + spec->automute_lo = 1; break; default: return -EINVAL; } - update_speakers(codec); + call_update_outputs(codec); return 1; } @@ -877,7 +907,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_auto_hp(struct hda_codec *codec) +static void alc_init_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -892,8 +922,6 @@ static void alc_init_auto_hp(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) { @@ -909,6 +937,8 @@ static void alc_init_auto_hp(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)) @@ -918,28 +948,32 @@ static void alc_init_auto_hp(struct hda_codec *codec) snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT); - 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->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_lines = spec->detect_line; + spec->automute_lo_possible = spec->detect_hp; } - if (spec->automute) { + 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) { /* create a control for automute mode */ alc_add_automute_mode_enum(codec); spec->unsol_event = alc_sku_unsol_event; @@ -1140,7 +1174,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_auto_hp(codec); + alc_init_automute(codec); alc_init_auto_mic(codec); } @@ -1320,7 +1354,9 @@ do_sku: * 15 : 1 --> enable the function "Mute internal speaker * when the external headphone out jack is plugged" */ - if (!spec->autocfg.hp_pins[0]) { + if (!spec->autocfg.hp_pins[0] && + !(spec->autocfg.line_out_pins[0] && + spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) { hda_nid_t nid; tmp = (ass >> 11) & 0x3; /* HP to chassis */ if (tmp == 0) @@ -1521,6 +1557,15 @@ 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 */ @@ -1559,27 +1604,29 @@ 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; + int i, err, nums; 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 (!i) { + if (!nums) { 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 (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) + if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) break; - spec->slave_dig_outs[i - 1] = dig_nid; + spec->slave_dig_outs[nums - 1] = dig_nid; } + nums++; } if (spec->autocfg.dig_in_pin) { @@ -1784,6 +1831,7 @@ static const char * const alc_slave_vols[] = { "Speaker Playback Volume", "Mono Playback Volume", "Line-Out Playback Volume", + "PCM Playback Volume", NULL, }; @@ -1798,6 +1846,7 @@ static const char * const alc_slave_sws[] = { "Mono Playback Switch", "IEC958 Playback Switch", "Line-Out Playback Switch", + "PCM Playback Switch", NULL, }; @@ -2223,6 +2272,7 @@ 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; @@ -2301,8 +2351,11 @@ 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 || spec->num_adc_nids > 1) { + if (spec->alt_dac_nid || have_multi_adcs) { codec->num_pcms = 3; info = spec->pcm_rec + 2; info->name = spec->stream_name_analog; @@ -2318,7 +2371,7 @@ static int alc_build_pcms(struct hda_codec *codec) alc_pcm_null_stream; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; } - if (spec->num_adc_nids > 1) { + if (have_multi_adcs) { p = spec->stream_analog_alt_capture; if (!p) p = &alc_pcm_analog_alt_capture; @@ -2359,6 +2412,18 @@ 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; @@ -2369,6 +2434,7 @@ 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); } @@ -2432,6 +2498,47 @@ static int alc_codec_rename(struct hda_codec *codec, const char *name) } /* + * 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 */ @@ -2439,11 +2546,15 @@ 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 */ @@ -2484,13 +2595,14 @@ 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 && @@ -2513,7 +2625,10 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, return "PCM"; break; } - return chname[ch]; + if (snd_BUG_ON(ch >= ARRAY_SIZE(channel_name))) + return "PCM"; + + return channel_name[ch]; } /* create input playback/capture controls for the given pin */ @@ -2548,7 +2663,6 @@ 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; @@ -2570,13 +2684,11 @@ 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; @@ -2777,8 +2889,9 @@ 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 (spec->multiout.hp_nid == nid) - continue; + if (found_in_nid_list(nid, spec->multiout.hp_out_nid, + ARRAY_SIZE(spec->multiout.hp_out_nid))) + continue; if (found_in_nid_list(nid, spec->multiout.extra_out_nid, ARRAY_SIZE(spec->multiout.extra_out_nid))) continue; @@ -2795,6 +2908,29 @@ 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) { @@ -2806,7 +2942,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_nid = 0; + spec->multiout.hp_out_nid[0] = 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; @@ -2817,7 +2953,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_nid = + spec->multiout.hp_out_nid[0] = get_dac_if_single(codec, cfg->hp_pins[0]); if (cfg->speaker_outs) spec->multiout.extra_out_nid[0] = @@ -2849,24 +2985,58 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); } - if (cfg->hp_outs && !spec->multiout.hp_nid) - spec->multiout.hp_nid = - alc_auto_look_for_dac(codec, cfg->hp_pins[0]); - if (cfg->speaker_outs && !spec->multiout.extra_out_nid[0]) - spec->multiout.extra_out_nid[0] = - alc_auto_look_for_dac(codec, cfg->speaker_pins[0]); + if (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); 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, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); + val); } #define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \ @@ -2879,6 +3049,7 @@ 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; @@ -2895,6 +3066,9 @@ 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); } @@ -2955,7 +3129,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) { + if (!name || !strcmp(name, "CLFE")) { /* Center/LFE */ err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1); if (err < 0) @@ -2981,23 +3155,24 @@ 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 */ - return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + 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); } sw = alc_look_for_out_mute_nid(codec, pin, dac); @@ -3011,20 +3186,112 @@ 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_out(codec, spec->autocfg.hp_pins[0], - spec->multiout.hp_nid, - "Headphone"); + return alc_auto_create_extra_outs(codec, spec->autocfg.hp_outs, + spec->autocfg.hp_pins, + spec->multiout.hp_out_nid, + "Headphone"); } static int alc_auto_create_speaker_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0], - spec->multiout.extra_out_nid[0], - "Speaker"); + return alc_auto_create_extra_outs(codec, spec->autocfg.speaker_outs, + spec->autocfg.speaker_pins, + spec->multiout.extra_out_nid, + "Speaker"); } static void alc_auto_set_output_and_unmute(struct hda_codec *codec, @@ -3081,16 +3348,39 @@ 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; - hda_nid_t pin; + int i; + hda_nid_t pin, 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]); + 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); + } } /* @@ -3101,6 +3391,7 @@ 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--) { @@ -3128,8 +3419,13 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec, } } spec->multiout.num_dacs = 1; - if (num_pins < 2) + 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; return 0; + } return num_pins; } @@ -3215,36 +3511,11 @@ 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, - int (*fill_dac)(struct hda_codec *)) +static int alc_auto_add_multi_channel_mode(struct hda_codec *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; - - 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) { + if (spec->multi_ios > 0) { struct snd_kcontrol_new *knew; knew = alc_kcontrol_new(spec); @@ -3254,10 +3525,6 @@ 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; } @@ -3540,27 +3807,42 @@ 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_def_config(codec, &spec->autocfg, - ignore_nids); + err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids, + spec->parse_flags); if (err < 0) return err; - if (!spec->autocfg.line_outs) { - if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { + if (!cfg->line_outs) { + if (cfg->dig_outs || cfg->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, alc_auto_fill_dac_nids); + err = alc_auto_add_multi_channel_mode(codec); if (err < 0) return err; - err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg); + err = alc_auto_create_multi_out_ctls(codec, cfg); if (err < 0) return err; err = alc_auto_create_hp_out(codec); @@ -3663,10 +3945,8 @@ 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) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS else if (!err) { printk(KERN_INFO @@ -3691,10 +3971,8 @@ static int patch_alc880(struct hda_codec *codec) if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } @@ -3709,6 +3987,10 @@ static int patch_alc880(struct hda_codec *codec) #endif return 0; + + error: + alc_free(codec); + return err; } @@ -3790,10 +4072,8 @@ 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) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS else if (!err) { printk(KERN_INFO @@ -3818,10 +4098,8 @@ static int patch_alc260(struct hda_codec *codec) if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); } @@ -3839,6 +4117,10 @@ static int patch_alc260(struct hda_codec *codec) #endif return 0; + + error: + alc_free(codec); + return err; } @@ -3865,6 +4147,7 @@ enum { PINFIX_LENOVO_Y530, PINFIX_PB_M5210, PINFIX_ACER_ASPIRE_7736, + PINFIX_ASUS_W90V, }; static const struct alc_fixup alc882_fixups[] = { @@ -3896,10 +4179,18 @@ 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), @@ -3946,6 +4237,10 @@ 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); @@ -3969,10 +4264,8 @@ 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) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS else if (!err) { printk(KERN_INFO @@ -3997,10 +4290,8 @@ 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) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } @@ -4019,6 +4310,10 @@ static int patch_alc882(struct hda_codec *codec) #endif return 0; + + error: + alc_free(codec); + return err; } @@ -4123,10 +4418,8 @@ 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) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS else if (!err) { printk(KERN_INFO @@ -4151,10 +4444,8 @@ 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) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } @@ -4174,6 +4465,10 @@ static int patch_alc262(struct hda_codec *codec) #endif return 0; + + error: + alc_free(codec); + return err; } /* @@ -4222,14 +4517,9 @@ 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); @@ -4240,38 +4530,10 @@ static int patch_alc268(struct hda_codec *codec) /* ALC268 has no aa-loopback mixer */ - 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]); + /* automatic parse from the BIOS config */ + err = alc268_parse_auto_config(codec); + if (err < 0) + goto error; has_beep = 0; for (i = 0; i < spec->num_mixers; i++) { @@ -4283,10 +4545,8 @@ static int patch_alc268(struct hda_codec *codec) if (has_beep) { err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) /* override the amp caps for beep generator */ snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, @@ -4308,13 +4568,16 @@ static int patch_alc268(struct hda_codec *codec) spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); return 0; + + error: + alc_free(codec); + return err; } /* @@ -4408,9 +4671,9 @@ static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) static void alc269_shutup(struct hda_codec *codec) { - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) + if ((alc_get_coef0(codec) & 0x00ff) == 0x017) alc269_toggle_power_output(codec, 0); - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { alc269_toggle_power_output(codec, 0); msleep(150); } @@ -4419,19 +4682,19 @@ static void alc269_shutup(struct hda_codec *codec) #ifdef CONFIG_PM static int alc269_resume(struct hda_codec *codec) { - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { alc269_toggle_power_output(codec, 0); msleep(150); } codec->patch_ops.init(codec); - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { + if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { alc269_toggle_power_output(codec, 1); msleep(200); } - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) + if ((alc_get_coef0(codec) & 0x00ff) == 0x018) alc269_toggle_power_output(codec, 1); snd_hda_codec_resume_amp(codec); @@ -4484,6 +4747,46 @@ 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, @@ -4494,6 +4797,13 @@ 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[] = { @@ -4556,23 +4866,144 @@ 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"}, {} }; @@ -4581,23 +5012,23 @@ static int alc269_fill_coef(struct hda_codec *codec) { int val; - if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) { + if ((alc_get_coef0(codec) & 0x00ff) < 0x015) { alc_write_coef_idx(codec, 0xf, 0x960b); alc_write_coef_idx(codec, 0xe, 0x8817); } - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) { + if ((alc_get_coef0(codec) & 0x00ff) == 0x016) { alc_write_coef_idx(codec, 0xf, 0x960b); alc_write_coef_idx(codec, 0xe, 0x8814); } - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { + if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { val = alc_read_coef_idx(codec, 0x04); /* Power up output pin */ alc_write_coef_idx(codec, 0x04, val | (1<<11)); } - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { val = alc_read_coef_idx(codec, 0xd); if ((val & 0x0c00) >> 10 != 0x1) { /* Capless ramp up clock control */ @@ -4621,15 +5052,10 @@ 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 board_config, coef; - int err; + int err = 0; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -4641,72 +5067,41 @@ 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; - coef = alc_read_coef_idx(codec, 0); - if ((coef & 0x00f0) == 0x0010) { + switch (alc_get_coef0(codec) & 0x00f0) { + case 0x0010: if (codec->bus->pci->subsystem_vendor == 0x1025 && - spec->cdefine.platform_type == 1) { - alc_codec_rename(codec, "ALC271X"); - } else if ((coef & 0xf000) == 0x2000) { - alc_codec_rename(codec, "ALC259"); - } else if ((coef & 0xf000) == 0x3000) { - alc_codec_rename(codec, "ALC258"); - } else if ((coef & 0xfff0) == 0x3010) { - alc_codec_rename(codec, "ALC277"); - } else { - alc_codec_rename(codec, "ALC269VB"); - } + spec->cdefine.platform_type == 1) + err = alc_codec_rename(codec, "ALC271X"); spec->codec_variant = ALC269_TYPE_ALC269VB; - } else if ((coef & 0x00f0) == 0x0020) { - if (coef == 0xa023) - alc_codec_rename(codec, "ALC259"); - else if (coef == 0x6023) - alc_codec_rename(codec, "ALC281X"); - else if (codec->bus->pci->subsystem_vendor == 0x17aa && - codec->bus->pci->subsystem_device == 0x21f3) - alc_codec_rename(codec, "ALC3202"); - else - alc_codec_rename(codec, "ALC269VC"); + break; + case 0x0020: + if (codec->bus->pci->subsystem_vendor == 0x17aa && + codec->bus->pci->subsystem_device == 0x21f3) + err = alc_codec_rename(codec, "ALC3202"); spec->codec_variant = ALC269_TYPE_ALC269VC; - } else + break; + default: alc_fix_pll_init(codec, 0x20, 0x04, 15); + } + if (err < 0) + goto error; alc269_fill_coef(codec); } - board_config = alc_board_config(codec, ALC269_MODEL_LAST, - alc269_models, alc269_cfg_tbl); - - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = 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); - } + alc_pick_fixup(codec, alc269_fixup_models, + 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]); + /* automatic parse from the BIOS config */ + err = alc269_parse_auto_config(codec); + if (err < 0) + goto error; if (!spec->no_analog && !spec->adc_nids) { alc_auto_fill_adc_caps(codec); @@ -4719,10 +5114,8 @@ 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) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); } @@ -4734,8 +5127,7 @@ static int patch_alc269(struct hda_codec *codec) #ifdef CONFIG_PM codec->patch_ops.resume = alc269_resume; #endif - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + spec->init_hook = alc_auto_init_std; spec->shutup = alc269_shutup; alc_init_jacks(codec); @@ -4747,6 +5139,10 @@ static int patch_alc269(struct hda_codec *codec) #endif return 0; + + error: + alc_free(codec); + return err; } /* @@ -4794,14 +5190,9 @@ 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); @@ -4812,39 +5203,13 @@ static int patch_alc861(struct hda_codec *codec) spec->mixer_nid = 0x15; - board_config = alc_board_config(codec, ALC861_MODEL_LAST, - alc861_models, alc861_cfg_tbl); - - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } - - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, 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 - } + 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) - setup_preset(codec, &alc861_presets[board_config]); + /* automatic parse from the BIOS config */ + err = alc861_parse_auto_config(codec); + if (err < 0) + goto error; if (!spec->no_analog && !spec->adc_nids) { alc_auto_fill_adc_caps(codec); @@ -4857,10 +5222,8 @@ static int patch_alc861(struct hda_codec *codec) if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x23); - if (err < 0) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); } @@ -4869,18 +5232,18 @@ static int patch_alc861(struct hda_codec *codec) alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) { - spec->init_hook = alc_auto_init_std; -#ifdef CONFIG_SND_HDA_POWER_SAVE - spec->power_hook = alc_power_eapd; -#endif - } + spec->init_hook = alc_auto_init_std; #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; } /* @@ -4902,24 +5265,41 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) } enum { - ALC660VD_FIX_ASUS_GPIO1 + ALC660VD_FIX_ASUS_GPIO1, + ALC861VD_FIX_DALLAS, }; -/* reset 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); + } +} + 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), {} }; @@ -4931,14 +5311,10 @@ 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, board_config; + int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -4948,39 +5324,13 @@ static int patch_alc861vd(struct hda_codec *codec) spec->mixer_nid = 0x0b; - board_config = alc_board_config(codec, ALC861VD_MODEL_LAST, - alc861vd_models, alc861vd_cfg_tbl); - - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } - - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } - - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc861vd_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC861VD_3ST; - } -#endif - } + 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) - setup_preset(codec, &alc861vd_presets[board_config]); + /* automatic parse from the BIOS config */ + err = alc861vd_parse_auto_config(codec); + if (err < 0) + goto error; if (codec->vendor_id == 0x10ec0660) { /* always turn on EAPD */ @@ -4998,10 +5348,8 @@ static int patch_alc861vd(struct hda_codec *codec) if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x23); - if (err < 0) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } @@ -5011,8 +5359,7 @@ static int patch_alc861vd(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) @@ -5020,6 +5367,10 @@ static int patch_alc861vd(struct hda_codec *codec) #endif return 0; + + error: + alc_free(codec); + return err; } /* @@ -5077,6 +5428,14 @@ 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[] = { @@ -5118,37 +5477,204 @@ 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, board_config; - int coef; + int err = 0; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) @@ -5158,50 +5684,31 @@ 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); - 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; - } + err = alc_codec_rename_from_preset(codec); + if (err < 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 + 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) - setup_preset(codec, &alc662_presets[board_config]); + 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 (!spec->no_analog && !spec->adc_nids) { alc_auto_fill_adc_caps(codec); @@ -5214,10 +5721,8 @@ 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) { - alc_free(codec); - return err; - } + if (err < 0) + goto error; switch (codec->vendor_id) { case 0x10ec0662: set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); @@ -5237,8 +5742,7 @@ static int patch_alc662(struct hda_codec *codec) alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); @@ -5249,32 +5753,10 @@ static int patch_alc662(struct hda_codec *codec) #endif return 0; -} - -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); + error: + alc_free(codec); + return err; } /* @@ -5288,14 +5770,9 @@ 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); @@ -5306,43 +5783,11 @@ static int patch_alc680(struct hda_codec *codec) /* ALC680 has no aa-loopback mixer */ - 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); + /* automatic parse from the BIOS config */ + err = alc680_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; } if (!spec->no_analog && !spec->cap_mixer) @@ -5351,8 +5796,7 @@ static int patch_alc680(struct hda_codec *codec) spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; + spec->init_hook = alc_auto_init_std; return 0; } @@ -5380,6 +5824,8 @@ 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 }, @@ -5392,13 +5838,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_alc888 }, + { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 }, { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200", .patch = patch_alc882 }, - { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 }, + { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 }, { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 }, { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 }, - { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 }, + { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index aa376b59c006..de4c36027cbe 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -673,6 +673,7 @@ 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) { @@ -696,6 +697,7 @@ 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) @@ -2970,8 +2972,9 @@ 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]; + hda_nid_t conn[HDA_MAX_CONNECTIONS], fallback_dac; unsigned int wcaps, wtype; conn_len = snd_hda_get_connections(codec, nid, conn, @@ -2999,10 +3002,21 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid) return conn[j]; } } - /* if all DACs are already assigned, connect to the primary DAC */ + + /* if 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 (conn_len > 1) { for (j = 0; j < conn_len; j++) { - if (conn[j] == spec->multiout.dac_nids[0]) { + if (conn[j] == fallback_dac) { snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, j); break; @@ -3777,9 +3791,10 @@ static int is_dual_headphones(struct hda_codec *codec) } -static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) +static int stac92xx_parse_auto_config(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; + hda_nid_t dig_out = 0, dig_in = 0; int hp_swap = 0; int i, err; @@ -3962,6 +3977,22 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out 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) @@ -4128,22 +4159,14 @@ 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; - 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 snd_hda_input_jack_add(codec, nid, type, NULL); +#else return 0; +#endif /* CONFIG_SND_HDA_INPUT_JACK */ } static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid, @@ -5273,7 +5296,7 @@ static int patch_stac925x(struct hda_codec *codec) spec->capvols = stac925x_capvols; spec->capsws = stac925x_capsws; - err = stac92xx_parse_auto_config(codec, 0x8, 0x7); + err = stac92xx_parse_auto_config(codec); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -5414,7 +5437,7 @@ again: spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); spec->pwr_nids = stac92hd73xx_pwr_nids; - err = stac92xx_parse_auto_config(codec, 0x25, 0x27); + err = stac92xx_parse_auto_config(codec); if (!err) { if (spec->board_config < 0) { @@ -5583,9 +5606,7 @@ 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) @@ -5625,25 +5646,8 @@ again: stac92xx_set_config_regs(codec, stac92hd83xxx_brd_tbl[spec->board_config]); - 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; + if (spec->board_config != STAC_92HD83XXX_PWR_REF) spec->num_pwrs = 0; - break; - } codec->patch_ops = stac92xx_patch_ops; @@ -5670,7 +5674,7 @@ again: } #endif - err = stac92xx_parse_auto_config(codec, 0x1d, 0); + err = stac92xx_parse_auto_config(codec); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -5686,22 +5690,6 @@ again: 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; @@ -6007,7 +5995,7 @@ again: spec->multiout.dac_nids = spec->dac_nids; - err = stac92xx_parse_auto_config(codec, 0x21, 0); + err = stac92xx_parse_auto_config(codec); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -6116,7 +6104,7 @@ static int patch_stac922x(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; - err = stac92xx_parse_auto_config(codec, 0x08, 0x09); + err = stac92xx_parse_auto_config(codec); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -6241,7 +6229,7 @@ static int patch_stac927x(struct hda_codec *codec) spec->aloopback_shift = 0; spec->eapd_switch = 1; - err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); + err = stac92xx_parse_auto_config(codec); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -6366,7 +6354,7 @@ static int patch_stac9205(struct hda_codec *codec) break; } - err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); + err = stac92xx_parse_auto_config(codec); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -6471,7 +6459,7 @@ static int patch_stac9872(struct hda_codec *codec) spec->capvols = stac9872_capvols; spec->capsws = stac9872_capsws; - err = stac92xx_parse_auto_config(codec, 0x10, 0x12); + err = stac92xx_parse_auto_config(codec); if (err < 0) { stac92xx_free(codec); return -EINVAL; @@ -6571,10 +6559,23 @@ 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/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 84d8798bf33a..0b020a93a8ed 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1506,39 +1506,49 @@ 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 = 1; + codec->num_pcms = 0; codec->pcm_info = info; - snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); - info->name = spec->stream_name_analog; + if (spec->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; - 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->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_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->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++; } - 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); @@ -1562,17 +1572,19 @@ 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; } @@ -2084,7 +2096,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; + hda_nid_t pin, dac = 0; int err; pin = spec->autocfg.speaker_pins[0]; @@ -3688,13 +3700,8 @@ 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/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 0ccc0eb75775..8531b983f3af 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2748,8 +2748,9 @@ 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), - ice->irq, 0, &ice->rmidi[0]); + c->mpu401_1_info_flags | + MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, + -1, &ice->rmidi[0]); if (err < 0) { snd_card_free(card); return err; @@ -2764,8 +2765,9 @@ 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), - ice->irq, 0, &ice->rmidi[1]); + c->mpu401_2_info_flags | + MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, + -1, &ice->rmidi[1]); if (err < 0) { snd_card_free(card); diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6a5b387b97fd..45b2055f5a76 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -42,6 +42,12 @@ #include <asm/pgtable.h> #include <asm/cacheflush.h> +#ifdef CONFIG_KVM_GUEST +#include <linux/kvm_para.h> +#else +#define kvm_para_available() (0) +#endif + MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455"); MODULE_LICENSE("GPL"); @@ -77,6 +83,7 @@ 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."); @@ -94,6 +101,8 @@ 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; @@ -400,6 +409,7 @@ 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 */ @@ -1065,8 +1075,11 @@ 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) && - ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) + 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)) break; } while (timeout--); ptr = ichdev->last_pos; @@ -2984,6 +2997,10 @@ 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 */ @@ -3226,6 +3243,14 @@ 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/sound/pci/maestro3.c b/sound/pci/maestro3.c index 0378126e6272..2fd4bf2d6653 100644 --- a/sound/pci/maestro3.c +++ b/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, - chip->irq, 0, &chip->rmidi); + MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, + -1, &chip->rmidi); if (err < 0) printk(KERN_WARNING "maestro3: no MIDI support.\n"); #endif diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 82311fcb86f6..53e5508abcbf 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/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; + unsigned int info_flags = + MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK; 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, 0, 0, - &chip->midi); + info_flags, -1, &chip->midi); if (err < 0) goto err_card; } diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 32d096c98f5b..8433aa7c3d75 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -1074,6 +1074,7 @@ 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/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index e34ae14908b3..88cc776aa38b 100644 --- a/sound/pci/riptide/riptide.c +++ b/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, 0, chip->irq, 0, + val, MPU401_INFO_IRQ_HOOK, -1, &chip->rmidi); if (err < 0) snd_printk(KERN_WARNING diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 1c6d1e1c27c1..f74220292254 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/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 +#define HDSP_VERSION_BIT (0x100 | HDSP_S_LOAD) #define HDSP_BIGENDIAN_MODE 0x200 #define HDSP_RD_MULTIPLE 0x400 #define HDSP_9652_ENABLE_MIXER 0x800 diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 6edc67ced905..15a6c3b9bc9a 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -520,16 +520,9 @@ 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 @@ -1241,10 +1234,30 @@ 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 = 1 << ((hdspm_decode_latency(hdspm->control_register) + 8)); + hdspm->period_bytes = 4 * hdspm_get_latency(hdspm); } @@ -1303,12 +1316,27 @@ static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames) spin_lock_irq(&s->lock); - frames >>= 7; - n = 0; - while (frames) { - n++; - frames >>= 1; + 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; + } } + s->control_register &= ~HDSPM_LatencyMask; s->control_register |= hdspm_encode_latency(n); @@ -1339,6 +1367,10 @@ 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); @@ -1356,16 +1388,19 @@ 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; + n = 104857600000000ULL; /* 100 MHz */ + break; + default: + snd_BUG(); + return; } n = div_u64(n, rate); @@ -4794,8 +4829,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, snd_iprintf(buffer, "--- Settings ---\n"); - x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & - HDSPM_LatencyMask)); + x = hdspm_get_latency(hdspm); snd_iprintf(buffer, "Size (Latency): %d samples (2 periods of %lu bytes)\n", @@ -4958,8 +4992,7 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, snd_iprintf(buffer, "--- Settings ---\n"); - x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & - HDSPM_LatencyMask)); + x = hdspm_get_latency(hdspm); snd_iprintf(buffer, "Size (Latency): %d samples (2 periods of %lu bytes)\n", @@ -5665,19 +5698,6 @@ 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 | @@ -5696,8 +5716,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 = (64 * 4), - .period_bytes_max = (4096 * 4) * HDSPM_MAX_CHANNELS, + .period_bytes_min = (32 * 4), + .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, .periods_min = 2, .periods_max = 512, .fifo_size = 0 @@ -5721,31 +5741,13 @@ 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 = (64 * 4), - .period_bytes_max = (4096 * 4) * HDSPM_MAX_CHANNELS, + .period_bytes_min = (32 * 4), + .period_bytes_max = (8192 * 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) { @@ -5946,26 +5948,29 @@ 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_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); - + 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); break; default: - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - &hw_constraints_period_sizes_old); + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + 64, 8192); + break; } 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 { @@ -6018,24 +6023,28 @@ 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_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; + 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; default: - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - &hw_constraints_period_sizes_old); + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + 64, 8192); + break; } 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 { @@ -6081,7 +6090,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 __user arg) + unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; struct hdspm *hdspm = hw->private_data; @@ -6206,11 +6215,13 @@ 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((void __user *) arg, &info, sizeof(info))) + if (copy_to_user(argp, &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); @@ -6235,7 +6246,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_TX_64ch) ? 1 : 0; + (statusregister & HDSPM_RX_64ch) ? 1 : 0; /* TODO: Mac driver sets it when f_s>48kHz */ status.card_specific.madi.frame_format = 0; @@ -6243,13 +6254,15 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, break; } - if (copy_to_user((void __user *) arg, &status, sizeof(status))) + if (copy_to_user(argp, &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)); @@ -6260,13 +6273,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((void __user *) arg, &hdspm_version, + if (copy_to_user(argp, &hdspm_version, sizeof(hdspm_version))) return -EFAULT; break; case SNDRV_HDSPM_IOCTL_GET_MIXER: - if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer))) + if (copy_from_user(&mixer, argp, sizeof(mixer))) return -EFAULT; if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer, sizeof(struct hdspm_mixer))) @@ -6483,13 +6496,6 @@ 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"; @@ -6505,17 +6511,25 @@ 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: - snd_printk(KERN_ERR "HDSPM: unknown firmware revision %x\n", + 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", hdspm->firmware_rev); - return -ENODEV; + return -ENODEV; + } } err = pci_enable_device(pci); diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index bcf61524a13f..5ffb20b18786 100644 --- a/sound/pci/sis7019.c +++ b/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_DISABLED|IRQF_SHARED, + if (request_irq(pci->irq, sis_interrupt, 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_DISABLED|IRQF_SHARED, + if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED, KBUILD_MODNAME, sis)) { printk(KERN_ERR "unable to allocate irq %d\n", sis->irq); goto error_out_cleanup; diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 2571a67b389a..c5008166cf1f 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -1493,9 +1493,10 @@ 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, - sonic->irq, 0, - &midi_uart)) < 0) { + sonic->midi_port, + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &midi_uart)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index d8a128f6fc02..5e707effdc7c 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -148,8 +148,9 @@ 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, - trident->irq, 0, &trident->rmidi)) < 0) { + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &trident->rmidi)) < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index f03fd620a2a0..c3656fffdb50 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1175,6 +1175,7 @@ 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; @@ -1196,6 +1197,7 @@ 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]; @@ -1212,6 +1214,12 @@ 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; @@ -2068,8 +2076,9 @@ 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, - chip->irq, 0, &chip->rmidi) < 0) { + mpu_port, MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, -1, + &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/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 511d57653124..3253b04da184 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -305,8 +305,9 @@ 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, - pci->irq, 0, &chip->rawmidi)) < 0) { + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &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/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index f3260e658b8a..66ea71b2a70d 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -897,6 +897,18 @@ 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) @@ -904,11 +916,8 @@ 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; } @@ -1013,6 +1022,18 @@ 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) @@ -1022,9 +1043,6 @@ 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); @@ -1615,7 +1633,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 Volume", 0, YDSXGR_LEGACYOUTVOL), +YMFPCI_DOUBLE("FM Legacy Playback 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/sound/ppc/keywest.c b/sound/ppc/keywest.c index 8f064c7ce745..4080becf4cef 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c @@ -82,7 +82,6 @@ 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/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index bc823a547550..775bd95d4be6 100644 --- a/sound/ppc/snd_ps3.c +++ b/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, IRQF_DISABLED, + ret = request_irq(the_card.irq_no, snd_ps3_interrupt, 0, SND_PS3_DRIVER_NAME, &the_card); if (ret) { pr_info("%s: request_irq failed (%d)\n", __func__, ret); diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c index 7aa5b7606777..177f7137a9c8 100644 --- a/sound/soc/au1x/dma.c +++ b/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, IRQF_DISABLED, + au1000_dma_interrupt, 0, &ctx->stream[s]); set_dma_mode(ctx->stream[s].dma, get_dma_mode(ctx->stream[s].dma) & ~DMA_NC); diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 3f4920d5456d..dc8a2b2bdc1c 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/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_DISABLED, + IRQF_TRIGGER_RISING, codec->name, codec); if (ret < 0) { dev_err(codec->dev, "Could not request IRQ%d (%d)\n", diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c index 4e3626b9d8f9..ae8d6806966b 100644 --- a/sound/soc/nuc900/nuc900-pcm.c +++ b/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, - IRQF_DISABLED, "nuc900-dma", substream)) + 0, "nuc900-dma", substream)) return -EBUSY; runtime->private_data = nuc900_audio; diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 65ea53884806..b5e922f469d5 100644 --- a/sound/soc/samsung/ac97.c +++ b/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, - IRQF_DISABLED, "AC97", NULL); + 0, "AC97", NULL); if (ret < 0) { dev_err(&pdev->dev, "ac97: interrupt request failed.\n"); goto err4; diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 916b9f99b7e7..a32fd16ad668 100644 --- a/sound/soc/sh/fsi.c +++ b/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, IRQF_DISABLED, + ret = request_irq(irq, &fsi_interrupt, 0, id_entry->name, master); if (ret) { dev_err(&pdev->dev, "irq request err\n"); diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index 743d07b82c06..a4e3f5501847 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/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, - IRQF_DISABLED, dev_name(&pdev->dev), drvdata); + 0, dev_name(&pdev->dev), drvdata); if (err < 0) return err; diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index ad7d4d7d9237..f036776380b5 100644 --- a/sound/sparc/amd7930.c +++ b/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_DISABLED | IRQF_SHARED, "amd7930", amd)) { + 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/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 1e3ae3327dd3..07bcfe4d18a7 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -16,6 +16,7 @@ #include <linux/firmware.h> #include <linux/bitrev.h> +#include <linux/kernel.h> #include "firmware.h" #include "chip.h" @@ -59,21 +60,19 @@ struct ihex_record { unsigned int txt_offset; /* current position in txt_data */ }; -static u8 usb6fire_fw_ihex_nibble(const u8 n) -{ - 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]); + 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; + *crc += val; return val; } diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 8beb77563da2..3efc21c3d67c 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -67,6 +67,7 @@ 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. @@ -85,6 +86,7 @@ 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/sound/usb/Makefile b/sound/usb/Makefile index cf9ed66445fa..ac256dc4c6be 100644 --- a/sound/usb/Makefile +++ b/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 \ - format.o \ - endpoint.o \ - urb.o \ - pcm.o \ - helper.o \ - clock.o + stream.o snd-usbmidi-lib-objs := midi.o diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index d0d493ca28ae..2cf87f5afed4 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -139,8 +139,12 @@ static void stream_stop(struct snd_usb_caiaqdev *dev) for (i = 0; i < N_URBS; i++) { usb_kill_urb(dev->data_urbs_in[i]); - usb_kill_urb(dev->data_urbs_out[i]); + + if (test_bit(i, &dev->outurb_active_mask)) + 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) @@ -612,8 +616,9 @@ static void read_completed(struct urb *urb) { struct snd_usb_caiaq_cb_info *info = urb->context; struct snd_usb_caiaqdev *dev; - struct urb *out; - int frame, len, send_it = 0, outframe = 0; + struct urb *out = NULL; + int i, frame, len, send_it = 0, outframe = 0; + size_t offset = 0; if (urb->status || !info) return; @@ -623,7 +628,17 @@ static void read_completed(struct urb *urb) if (!dev->streaming) return; - out = dev->data_urbs_out[info->index]; + /* 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; + } /* read the recently received packet and send back one which has * the same layout */ @@ -634,7 +649,8 @@ 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 = BYTES_PER_FRAME * frame; + out->iso_frame_desc[outframe].offset = offset; + offset += len; if (len > 0) { spin_lock(&dev->spinlock); @@ -650,11 +666,15 @@ static void read_completed(struct urb *urb) } if (send_it) { - out->number_of_packets = FRAMES_PER_URB; + out->number_of_packets = outframe; 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; @@ -676,6 +696,8 @@ 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) @@ -827,6 +849,9 @@ 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/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index 45bc4a2dc6f0..3eb605bd9503 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -50,7 +50,8 @@ 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, Traktor Kontrol S4}" + "{Native Instruments, Maschine Controller}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ @@ -146,6 +147,11 @@ 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/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h index b2b310194ffa..562b0bff9c41 100644 --- a/sound/usb/caiaq/device.h +++ b/sound/usb/caiaq/device.h @@ -18,6 +18,7 @@ #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 @@ -96,6 +97,7 @@ 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/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index 4432ef7a70a9..26a121b42c3c 100644 --- a/sound/usb/caiaq/input.c +++ b/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_5, KEY_6 }; + KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 }; static unsigned short keycode_kore[] = { KEY_FN_F1, /* "menu" */ @@ -67,6 +67,61 @@ 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) @@ -218,6 +273,29 @@ 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; } } @@ -400,6 +478,25 @@ 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; @@ -425,6 +522,13 @@ 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: @@ -444,6 +548,7 @@ 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; @@ -462,6 +567,7 @@ 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; } @@ -652,6 +758,50 @@ 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; @@ -664,15 +814,17 @@ 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; } @@ -688,4 +840,3 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) input_unregister_device(dev->input_dev); dev->input_dev = NULL; } - diff --git a/sound/usb/card.c b/sound/usb/card.c index 781d9e61adfb..c1575eafff12 100644 --- a/sound/usb/card.c +++ b/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 <tiwai@suse.de>"); 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_endpoints(chip, interface)) { + if (! snd_usb_parse_audio_interface(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,8 +530,11 @@ snd_usb_audio_probe(struct usb_device *dev, return chip; __error: - if (chip && !chip->num_interfaces) - snd_card_free(chip->card); + if (chip) { + if (!chip->num_interfaces) + snd_card_free(chip->card); + chip->probing = 0; + } mutex_unlock(®ister_mutex); __err_val: return NULL; diff --git a/sound/usb/card.h b/sound/usb/card.h index ae4251d5abf7..a39edcc32a93 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -94,6 +94,8 @@ 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/sound/usb/clock.c b/sound/usb/clock.c index 075195e8661a..379baad3d5ad 100644 --- a/sound/usb/clock.c +++ b/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), 1000); + &buf, sizeof(buf)); 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), 1000); + &data, sizeof(data)); 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), 1000)) < 0) { + data, sizeof(data))) < 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), 1000)) < 0) { + data, sizeof(data))) < 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), 1000)) < 0) { + data, sizeof(data))) < 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), 1000)) < 0) { + data, sizeof(data))) < 0) { snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", dev->devnum, iface, fmt->altsetting); return err; diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 7c0d21ecd821..81c6edecd862 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -15,436 +15,951 @@ * */ +#include <linux/gfp.h> #include <linux/init.h> -#include <linux/slab.h> #include <linux/usb.h> #include <linux/usb/audio.h> -#include <linux/usb/audio-v2.h> #include <sound/core.h> #include <sound/pcm.h> #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" /* - * free a substream + * convert a sampling rate into our full speed format (fs/1000 in Q16.16) + * this will overflow at approx 524 kHz */ -static void free_substream(struct snd_usb_substream *subs) +static inline unsigned get_usb_full_speed_rate(unsigned int rate) { - 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); + 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; +} /* - * free a usb stream instance + * unlink active urbs. */ -static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) +static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep) { - free_substream(&stream->substream[0]); - free_substream(&stream->substream[1]); - list_del(&stream->list); - kfree(stream); + 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; } -static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) + +/* + * release a urb data + */ +static void release_urb_ctx(struct snd_urb_ctx *u) { - struct snd_usb_stream *stream = pcm->private_data; - if (stream) { - stream->pcm = NULL; - snd_usb_audio_stream_free(stream); + 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; +} /* - * 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. + * release a substream */ -int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp) +void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force) { - struct list_head *p; - struct snd_usb_stream *as; - struct snd_usb_substream *subs; - struct snd_pcm *pcm; - int err; + 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; +} - 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; +/* + * 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); } } - /* 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; +} + + +/* + * 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); + } } +} + - /* 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; +/* + * 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); } - 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); + subs->phase = 0; + + if (subs->fill_max) + subs->curpacksize = subs->maxpacksize; else - strcpy(pcm->name, "USB Audio"); + subs->curpacksize = maxsize; - snd_usb_init_substream(as, stream, fp); + 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; + } - list_add(&as->list, &chip->pcm_list); - chip->pcm_devs++; + /* 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; - snd_usb_proc_pcm_format_add(as); +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; } -static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, - struct usb_host_interface *alts, - int protocol, int iface_no) +/* + * 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) { - /* 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; - } + 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; +} - if (protocol == UAC_VERSION_1) { - attributes = csep->bmAttributes; - } else { - struct uac2_iso_endpoint_descriptor *csep2 = - (struct uac2_iso_endpoint_descriptor *) csep; +/* + * 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; +} - attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX; +/* + * 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; +} - /* emulate the endpoint attributes of a v1 device */ - if (csep2->bmControls & UAC2_CONTROL_PITCH) - attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL; +/* + * 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; +} - return attributes; +/* + * 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; } -static struct uac2_input_terminal_descriptor * - snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id) + +/* + * 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 uac2_input_terminal_descriptor *term = NULL; + 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; +} - while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, - ctrl_iface->extralen, - term, UAC_INPUT_TERMINAL))) { - if (term->bTerminalID == terminal_id) - return term; +/* + * 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 NULL; + return 0; } -static struct uac2_output_terminal_descriptor * - snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id) +/* determine the number of frames in the next packet */ +static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) { - 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; + if (subs->fill_max) + return subs->maxframesize; + else { + subs->phase = (subs->phase & 0xffff) + + (subs->freqm << subs->datainterval); + return min(subs->phase >> 16, subs->maxframesize); } +} - return 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; + } + 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; } -int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) +/* + * 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) { - 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; + 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; +} - dev = chip->dev; +/* + * 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; + int est_delay; - /* parse the interface's altsettings */ - iface = usb_ifnum_to_if(dev, iface_no); + spin_lock_irqsave(&subs->lock, flags); - num = iface->num_altsetting; + 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; /* - * Dallas DS4201 workaround: It presents 5 altsettings, but the last - * one misses syncpipe, and does not produce any sound. + * 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. */ - 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 (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); - if (as->bLength < sizeof(*as)) { - snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", - dev->devnum, iface_no, altno); - continue; - } + spin_unlock_irqrestore(&subs->lock, flags); + return 0; +} - format = le16_to_cpu(as->wFormatTag); /* remember the format value */ - break; - } +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"; + } +} - 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); +/* + * 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 (!as) { - snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", - dev->devnum, iface_no, altno); - continue; + 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; } + } + } - if (as->bLength < sizeof(*as)) { - snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\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; } + set_bit(i + 16, &subs->active_mask); + } + } + return 0; - num_channels = as->bNrChannels; - format = le32_to_cpu(as->bmFormats); + __error: + // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); + deactivate_urbs(subs, 0, 0); + return -EPIPE; +} - /* 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; - } +/* + */ +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, + }, +}; - snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n", - dev->devnum, iface_no, altno, as->bTerminalLink); - continue; - } - } +/* + * initialize the substream instance. + */ - /* 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; - } +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; +} - /* - * 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_playback_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_usb_substream *subs = substream->runtime->private_data; - 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; - } + 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; + } - /* 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; - } + return -EINVAL; +} - 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); +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/sound/usb/endpoint.h b/sound/usb/endpoint.h index 64dd0db023b2..88eb63a636eb 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -1,11 +1,21 @@ #ifndef __USBAUDIO_ENDPOINT_H #define __USBAUDIO_ENDPOINT_H -int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, - int iface_no); +void snd_usb_init_substream(struct snd_usb_stream *as, + int stream, + struct audioformat *fp); -int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, - 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_ENDPOINT_H */ diff --git a/sound/usb/format.c b/sound/usb/format.c index 8d042dce0d16..89421d176570 100644 --- a/sound/usb/format.c +++ b/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), 1000); + tmp, sizeof(tmp)); 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, 1000); + data, data_size); if (ret < 0) { snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n", diff --git a/sound/usb/helper.c b/sound/usb/helper.c index f280c1903c25..9eed8f40b179 100644 --- a/sound/usb/helper.c +++ b/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, int timeout) + __u16 size) { 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, timeout); + value, index, buf, size, 1000); if (size > 0) { memcpy(data, buf, size); kfree(buf); diff --git a/sound/usb/helper.h b/sound/usb/helper.h index 09bd943c43bf..805c300dd004 100644 --- a/sound/usb/helper.h +++ b/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, int timeout); + void *data, __u16 size); unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, struct usb_host_interface *alts); diff --git a/sound/usb/midi.c b/sound/usb/midi.c index f9289102886a..e21f026d9577 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -816,6 +816,22 @@ 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) { @@ -2163,6 +2179,17 @@ 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/sound/usb/mixer.c b/sound/usb/mixer.c index c22fa76e363a..60f65ace7474 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -152,6 +152,7 @@ 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; } } @@ -295,7 +296,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, 100) >= val_len) { + buf, val_len) >= val_len) { *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); snd_usb_autosuspend(cval->mixer->chip); return 0; @@ -332,7 +333,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, 1000); + buf, size); snd_usb_autosuspend(chip); if (ret < 0) { @@ -444,7 +445,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, 100) >= 0) { + buf, val_len) >= 0) { snd_usb_autosuspend(chip); return 0; } @@ -880,8 +881,17 @@ 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) { + 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); + } + } uinfo->value.integer.min = 0; uinfo->value.integer.max = (cval->max - cval->min + cval->res - 1) / cval->res; @@ -1092,7 +1102,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) { + if (cval->dBmin < cval->dBmax || !cval->initialized) { kctl->tlv.c = mixer_vol_tlv; kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ | @@ -1191,6 +1201,11 @@ 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 { @@ -1244,7 +1259,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 < 30/2; i++) { + for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) { unsigned int ch_bits = 0; unsigned int ch_read_only = 0; @@ -1934,15 +1949,13 @@ 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 = hostif->extra; - state.buflen = hostif->extralen; + state.buffer = mixer->hostif->extra; + state.buflen = mixer->hostif->extralen; /* check the mapping table */ for (map = usbmix_ctl_maps; map->id; map++) { @@ -1955,7 +1968,8 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) } p = NULL; - while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { + while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, mixer->hostif->extralen, + p, UAC_OUTPUT_TERMINAL)) != NULL) { if (mixer->protocol == UAC_VERSION_1) { struct uac1_output_terminal_descriptor *desc = p; @@ -2162,17 +2176,15 @@ 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(hostif)->bNumEndpoints < 1) + if (get_iface_desc(mixer->hostif)->bNumEndpoints < 1) return 0; - ep = get_endpoint(hostif, 0); + ep = get_endpoint(mixer->hostif, 0); if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_int(ep)) return 0; @@ -2202,7 +2214,6 @@ 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"); @@ -2219,8 +2230,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, return -ENOMEM; } - host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; - switch (get_iface_desc(host_iface)->bInterfaceProtocol) { + mixer->hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; + switch (get_iface_desc(mixer->hostif)->bInterfaceProtocol) { case UAC_VERSION_1: default: mixer->protocol = UAC_VERSION_1; diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index ae1a14dcfe82..81b2d8a32fb0 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -3,6 +3,7 @@ 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/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 3d0f4873112b..ab125ee0b0f0 100644 --- a/sound/usb/mixer_quirks.c +++ b/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, 100); + !value, 0, NULL, 0); /* USB X-Fi S51 Pro */ if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - !value, 0, NULL, 0, 100); + !value, 0, NULL, 0); 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, 100); + value, index + 2, NULL, 0); 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, 100); + jacks[i].unitid << 8, buf, 3); 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, 100); + 50, 0, &new_status, 1); if (err < 0) return err; mixer->xonar_u1_status = new_status; diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index b8dcbf407bbb..0220b0f335b9 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -28,12 +28,36 @@ #include "card.h" #include "quirks.h" #include "debug.h" -#include "urb.h" +#include "endpoint.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. */ @@ -45,6 +69,8 @@ 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); } @@ -126,7 +152,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), 1000)) < 0) { + data, sizeof(data))) < 0) { snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", dev->devnum, iface, ep); return err; @@ -150,7 +176,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), 1000)) < 0) { + data, sizeof(data))) < 0) { snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n", dev->devnum, iface, fmt->altsetting); return err; @@ -417,6 +443,8 @@ 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/sound/usb/pcm.h b/sound/usb/pcm.h index ed3e283f618d..df7a003682ad 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h @@ -1,6 +1,9 @@ #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/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index dba0b7f11c54..b61945f3af9e 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -39,6 +39,17 @@ .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), @@ -1678,6 +1689,20 @@ 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) { /* .vendor_name = "BOSS", */ @@ -1707,6 +1732,40 @@ 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 */ { @@ -2417,6 +2476,12 @@ 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/sound/usb/quirks.c b/sound/usb/quirks.c index 77762c99afbe..2e5bc7344026 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -34,6 +34,7 @@ #include "endpoint.h" #include "pcm.h" #include "clock.h" +#include "stream.h" /* * handle the quirks for the contained interfaces @@ -106,7 +107,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_endpoints(chip, altsd->bInterfaceNumber); + err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber); if (err < 0) { snd_printk(KERN_ERR "cannot setup if %d: error %d\n", altsd->bInterfaceNumber, err); @@ -147,7 +148,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_endpoint(chip, stream, fp); + err = snd_usb_add_audio_stream(chip, stream, fp); if (err < 0) { kfree(fp); kfree(rate_table); @@ -254,7 +255,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_endpoint(chip, stream, fp); + err = snd_usb_add_audio_stream(chip, stream, fp); if (err < 0) { kfree(fp); return err; @@ -306,6 +307,7 @@ 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, @@ -338,7 +340,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, 1000); + 0x10, 0x43, 0x0001, 0x000a, NULL, 0); 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)); @@ -359,11 +361,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, 1000); + 0, 0, &buf, 1); 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, 1000); + 1, 2000, NULL, 0); return -ENODEV; } return 0; @@ -406,7 +408,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, 1000); + 0, 0, &buf, 4); } static int snd_usb_cm106_boot_quirk(struct usb_device *dev) @@ -426,7 +428,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, reg; + int err = 0, reg; int val[] = {0x2004, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; for (reg = 0; reg < ARRAY_SIZE(val); reg++) { diff --git a/sound/usb/stream.c b/sound/usb/stream.c new file mode 100644 index 000000000000..5ff8010b2d6f --- /dev/null +++ b/sound/usb/stream.c @@ -0,0 +1,452 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h> + +#include <sound/core.h> +#include <sound/pcm.h> + +#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/sound/usb/stream.h b/sound/usb/stream.h new file mode 100644 index 000000000000..c97f679fc84f --- /dev/null +++ b/sound/usb/stream.h @@ -0,0 +1,12 @@ +#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/sound/usb/urb.c b/sound/usb/urb.c deleted file mode 100644 index e184349aee83..000000000000 --- a/sound/usb/urb.c +++ /dev/null @@ -1,941 +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 <linux/gfp.h> -#include <linux/init.h> -#include <linux/usb.h> -#include <linux/usb/audio.h> - -#include <sound/core.h> -#include <sound/pcm.h> - -#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/sound/usb/urb.h b/sound/usb/urb.h deleted file mode 100644 index 888da38079cf..000000000000 --- a/sound/usb/urb.h +++ /dev/null @@ -1,21 +0,0 @@ -#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/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 1e79986b5777..3e2b03577936 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -80,6 +80,7 @@ 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, |