diff options
-rw-r--r-- | sound/core/control.c | 2 | ||||
-rw-r--r-- | sound/core/info.c | 4 | ||||
-rw-r--r-- | sound/core/init.c | 8 | ||||
-rw-r--r-- | sound/core/pcm.c | 10 | ||||
-rw-r--r-- | sound/core/pcm_native.c | 4 | ||||
-rw-r--r-- | sound/core/rawmidi.c | 2 | ||||
-rw-r--r-- | sound/core/rtctimer.c | 4 | ||||
-rw-r--r-- | sound/core/sound_oss.c | 2 | ||||
-rw-r--r-- | sound/core/timer.c | 4 | ||||
-rw-r--r-- | sound/drivers/opl3/opl3_synth.c | 2 | ||||
-rw-r--r-- | sound/drivers/pcsp/pcsp_input.c | 1 | ||||
-rw-r--r-- | sound/oss/pas2.h | 3 | ||||
-rw-r--r-- | sound/oss/pas2_card.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 6 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.h | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 25 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 31 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 810 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 78 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 8 | ||||
-rw-r--r-- | sound/pci/lx6464es/lx_core.c | 84 | ||||
-rw-r--r-- | sound/usb/card.c | 18 | ||||
-rw-r--r-- | sound/usb/mixer.c | 99 | ||||
-rw-r--r-- | sound/usb/mixer.h | 7 |
24 files changed, 608 insertions, 607 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index d8aa206..c228f00 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -151,7 +151,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, if (snd_BUG_ON(!card || !id)) return; read_lock(&card->ctl_files_rwlock); -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS) card->mixer_oss_change_count++; #endif list_for_each_entry(ctl, &card->ctl_files, list) { diff --git a/sound/core/info.c b/sound/core/info.c index e79baa1..7916c07 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -540,7 +540,7 @@ int __init snd_info_init(void) snd_oss_root = entry; } #endif -#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) { struct snd_info_entry *entry; if ((entry = snd_info_create_module_entry(THIS_MODULE, "seq", NULL)) == NULL) @@ -567,7 +567,7 @@ int __exit snd_info_done(void) snd_minor_info_done(); snd_info_version_done(); if (snd_proc_root) { -#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) snd_info_free_entry(snd_seq_root); #endif #ifdef CONFIG_SND_OSSEMUL diff --git a/sound/core/init.c b/sound/core/init.c index 0d42fcd..a16d765 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -94,7 +94,7 @@ static int module_slot_match(struct module *module, int idx) return match; } -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS) int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); EXPORT_SYMBOL(snd_mixer_oss_notify_callback); #endif @@ -394,7 +394,7 @@ int snd_card_disconnect(struct snd_card *card) /* phase 3: notify all connected devices about disconnection */ /* at this point, they cannot respond to any calls except release() */ -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_DISCONNECT); #endif @@ -430,7 +430,7 @@ EXPORT_SYMBOL(snd_card_disconnect); */ static int snd_card_do_free(struct snd_card *card) { -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); #endif @@ -723,7 +723,7 @@ int snd_card_register(struct snd_card *card) snd_cards[card->number] = card; mutex_unlock(&snd_card_mutex); init_info_for_card(card); -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_MIXER_OSS) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER); #endif diff --git a/sound/core/pcm.c b/sound/core/pcm.c index e1e9e0c..091a05c 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -295,7 +295,7 @@ static const char *snd_pcm_state_name(snd_pcm_state_t state) return snd_pcm_state_names[(__force int)state]; } -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) #include <linux/soundcard.h> static const char *snd_pcm_oss_format_name(int format) @@ -398,7 +398,7 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den); snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size); snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size); -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) if (substream->oss.oss) { snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format)); snd_iprintf(buffer, "OSS channels: %u\n", runtime->oss.channels); @@ -651,7 +651,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) struct snd_pcm_str *pstr = &pcm->streams[stream]; struct snd_pcm_substream *substream, *prev; -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) mutex_init(&pstr->oss.setup_mutex); #endif pstr->stream = stream; @@ -807,7 +807,7 @@ EXPORT_SYMBOL(snd_pcm_new_internal); static void snd_pcm_free_stream(struct snd_pcm_str * pstr) { struct snd_pcm_substream *substream, *substream_next; -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) struct snd_pcm_oss_setup *setup, *setupn; #endif substream = pstr->substream; @@ -819,7 +819,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) substream = substream_next; } snd_pcm_stream_proc_done(pstr); -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) for (setup = pstr->oss.setup_list; setup; setup = setupn) { setupn = setup->next; kfree(setup->task_name); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 01a5e05..e366411 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -399,7 +399,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, return -EBADFD; } snd_pcm_stream_unlock_irq(substream); -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) +#if IS_ENABLED(CONFIG_SND_PCM_OSS) if (!substream->oss.oss) #endif if (atomic_read(&substream->mmap_count)) @@ -954,7 +954,7 @@ static struct action_ops snd_pcm_action_stop = { * * The state of each stream is then changed to the given state unconditionally. * - * Return: Zero if succesful, or a negative error code. + * Return: Zero if successful, or a negative error code. */ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state) { diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 7b596b5..f016be7 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1101,7 +1101,7 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, /** * snd_rawmidi_transmit_ack - acknowledge the transmission * @substream: the rawmidi substream - * @count: the tranferred count + * @count: the transferred count * * Advances the hardware pointer for the internal output buffer with * the given size and updates the condition. diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c index e85e72b..b272237 100644 --- a/sound/core/rtctimer.c +++ b/sound/core/rtctimer.c @@ -27,7 +27,7 @@ #include <sound/core.h> #include <sound/timer.h> -#if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE) +#if IS_ENABLED(CONFIG_RTC) #include <linux/mc146818rtc.h> @@ -185,4 +185,4 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_RTC)); -#endif /* CONFIG_RTC || CONFIG_RTC_MODULE */ +#endif /* IS_ENABLED(CONFIG_RTC) */ diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 726a49a..5391c5e 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -21,7 +21,7 @@ #ifdef CONFIG_SND_OSSEMUL -#if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE)) +#if !IS_ENABLED(CONFIG_SOUND) #error "Enable the OSS soundcore multiplexer (CONFIG_SOUND) in the kernel." #endif diff --git a/sound/core/timer.c b/sound/core/timer.c index 6ddcf06..cbec514 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -35,9 +35,9 @@ #include <sound/initval.h> #include <linux/kmod.h> -#if defined(CONFIG_SND_HRTIMER) || defined(CONFIG_SND_HRTIMER_MODULE) +#if IS_ENABLED(CONFIG_SND_HRTIMER) #define DEFAULT_TIMER_LIMIT 4 -#elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE) +#elif IS_ENABLED(CONFIG_SND_RTCTIMER) #define DEFAULT_TIMER_LIMIT 2 #else #define DEFAULT_TIMER_LIMIT 1 diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c index 742a4b6..ddcc1a3 100644 --- a/sound/drivers/opl3/opl3_synth.c +++ b/sound/drivers/opl3/opl3_synth.c @@ -24,7 +24,7 @@ #include <sound/opl3.h> #include <sound/asound_fm.h> -#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) +#if IS_ENABLED(CONFIG_SND_SEQUENCER) #define OPL3_SUPPORT_SYNTH #endif diff --git a/sound/drivers/pcsp/pcsp_input.c b/sound/drivers/pcsp/pcsp_input.c index b874b0a..0ecf8a4 100644 --- a/sound/drivers/pcsp/pcsp_input.c +++ b/sound/drivers/pcsp/pcsp_input.c @@ -16,6 +16,7 @@ #include <linux/input.h> #include <asm/io.h> #include "pcsp.h" +#include "pcsp_input.h" static void pcspkr_do_sound(unsigned int count) { diff --git a/sound/oss/pas2.h b/sound/oss/pas2.h index fa12c55..d19f757 100644 --- a/sound/oss/pas2.h +++ b/sound/oss/pas2.h @@ -15,3 +15,6 @@ int pas_init_mixer(void); /* From pas_midi.c */ void pas_midi_init(void); void pas_midi_interrupt(void); + +/* From pas2_mixer.c*/ +void mix_write(unsigned char data, int ioaddr); diff --git a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c index 7004e24..b07954a 100644 --- a/sound/oss/pas2_card.c +++ b/sound/oss/pas2_card.c @@ -74,8 +74,6 @@ static char *pas_model_names[] = { * to support other than the default base address */ -extern void mix_write(unsigned char data, int ioaddr); - unsigned char pas_read(int ioaddr) { return inb(ioaddr + pas_translate_code); diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index d9a09bd..bcd9c71 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -79,7 +79,7 @@ static void free_kctls(struct hda_gen_spec *spec) snd_array_free(&spec->kctls); } -void snd_hda_gen_spec_free(struct hda_gen_spec *spec) +static void snd_hda_gen_spec_free(struct hda_gen_spec *spec) { if (!spec) return; @@ -87,7 +87,6 @@ void snd_hda_gen_spec_free(struct hda_gen_spec *spec) snd_array_free(&spec->paths); snd_array_free(&spec->loopback_list); } -EXPORT_SYMBOL_GPL(snd_hda_gen_spec_free); /* * store user hints @@ -762,7 +761,7 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, AC_PWRST_D0); } if (enable && path->multi[i]) - snd_hda_codec_write_cache(codec, nid, 0, + snd_hda_codec_update_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, path->idx[i]); if (has_amp_in(codec, path, i)) @@ -5350,6 +5349,7 @@ EXPORT_SYMBOL_GPL(snd_hda_gen_init); */ void snd_hda_gen_free(struct hda_codec *codec) { + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE); snd_hda_detach_beep_device(codec); snd_hda_gen_spec_free(codec->spec); kfree(codec->spec); diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index c908afb..bb2dea7 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -297,7 +297,6 @@ struct hda_gen_spec { }; int snd_hda_gen_spec_init(struct hda_gen_spec *spec); -void snd_hda_gen_spec_free(struct hda_gen_spec *spec); int snd_hda_gen_init(struct hda_codec *codec); void snd_hda_gen_free(struct hda_codec *codec); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e354ab1..d8d9bf3 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -834,18 +834,6 @@ static unsigned int azx_command_addr(u32 cmd) return addr; } -static unsigned int azx_response_addr(u32 res) -{ - unsigned int addr = res & 0xf; - - if (addr >= AZX_MAX_CODECS) { - snd_BUG(); - addr = 0; - } - - return addr; -} - /* send a command */ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) { @@ -907,8 +895,15 @@ static void azx_update_rirb(struct azx *chip) rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); res = le32_to_cpu(chip->rirb.buf[rp]); - addr = azx_response_addr(res_ex); - if (res_ex & ICH6_RIRB_EX_UNSOL_EV) + addr = res_ex & 0xf; + if ((addr >= AZX_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) { + snd_printk(KERN_ERR SFX "%s: spurious response %#x:%#x, rp = %d, wp = %d", + pci_name(chip->pci), + res, res_ex, + chip->rirb.rp, wp); + snd_BUG(); + } + else if (res_ex & ICH6_RIRB_EX_UNSOL_EV) snd_hda_queue_unsol_event(chip->bus, res, res_ex); else if (chip->rirb.cmds[addr]) { chip->rirb.res[addr] = res; @@ -4142,7 +4137,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA }, { PCI_DEVICE(0x1102, 0x0012), .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA }, -#if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE) +#if !IS_ENABLED(CONFIG_SND_CTXFI) /* the following entry conflicts with snd-ctxfi driver, * as ctxfi driver mutates from HD-audio to native mode with * a special command sequence. diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 9c6ce73..139ef30 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -32,6 +32,9 @@ #include "hda_jack.h" #include "hda_generic.h" +#undef ENABLE_CMI_STATIC_QUIRKS + +#ifdef ENABLE_CMI_STATIC_QUIRKS #define NUM_PINS 11 @@ -45,10 +48,12 @@ enum { CMI_AUTO, /* let driver guess it */ CMI_MODELS }; +#endif /* ENABLE_CMI_STATIC_QUIRKS */ struct cmi_spec { struct hda_gen_spec gen; +#ifdef ENABLE_CMI_STATIC_QUIRKS /* below are only for static models */ int board_config; @@ -81,8 +86,10 @@ struct cmi_spec { /* multichannel pins */ struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ +#endif /* ENABLE_CMI_STATIC_QUIRKS */ }; +#ifdef ENABLE_CMI_STATIC_QUIRKS /* * input MUX */ @@ -566,6 +573,7 @@ static const struct hda_codec_ops cmi9880_patch_ops = { .init = cmi9880_init, .free = cmi9880_free, }; +#endif /* ENABLE_CMI_STATIC_QUIRKS */ /* * stuff for auto-parser @@ -588,15 +596,20 @@ static int cmi_parse_auto_config(struct hda_codec *codec) err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); if (err < 0) - return err; + goto error; err = snd_hda_gen_parse_auto_config(codec, cfg); if (err < 0) - return err; + goto error; codec->patch_ops = cmi_auto_patch_ops; return 0; + + error: + snd_hda_gen_free(codec); + return err; } + static int patch_cmi9880(struct hda_codec *codec) { struct cmi_spec *spec; @@ -606,6 +619,7 @@ static int patch_cmi9880(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; +#ifdef ENABLE_CMI_STATIC_QUIRKS spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS, cmi9880_models, cmi9880_cfg_tbl); @@ -615,14 +629,8 @@ static int patch_cmi9880(struct hda_codec *codec) spec->board_config = CMI_AUTO; /* try everything */ } - if (spec->board_config == CMI_AUTO) { - int err = cmi_parse_auto_config(codec); - if (err < 0) { - snd_hda_gen_free(codec); - return err; - } - return 0; - } + if (spec->board_config == CMI_AUTO) + return cmi_parse_auto_config(codec); /* copy default DAC NIDs */ memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); @@ -669,6 +677,9 @@ static int patch_cmi9880(struct hda_codec *codec) codec->patch_ops = cmi9880_patch_ops; return 0; +#else + return cmi_parse_auto_config(codec); +#endif } /* diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index bcf91be..59e3aea 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -35,7 +35,7 @@ #include "hda_jack.h" #include "hda_generic.h" -#define ENABLE_CXT_STATIC_QUIRKS +#undef ENABLE_CXT_STATIC_QUIRKS #define CXT_PIN_DIR_IN 0x00 #define CXT_PIN_DIR_OUT 0x01 @@ -68,6 +68,12 @@ struct conexant_spec { unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ + /* OPLC XO specific */ + bool recording; + bool dc_enable; + unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ + struct nid_path *dc_mode_path; + #ifdef ENABLE_CXT_STATIC_QUIRKS const struct snd_kcontrol_new *mixers[5]; int num_mixers; @@ -123,19 +129,6 @@ struct conexant_spec { unsigned int hp_laptop:1; unsigned int asus:1; - unsigned int ext_mic_present; - unsigned int recording; - void (*capture_prepare)(struct hda_codec *codec); - void (*capture_cleanup)(struct hda_codec *codec); - - /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) - * through the microphone jack. - * When the user enables this through a mixer switch, both internal and - * external microphones are disabled. Gain is fixed at 0dB. In this mode, - * we also allow the bias to be configured through a separate mixer - * control. */ - unsigned int dc_enable; - unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ #endif /* ENABLE_CXT_STATIC_QUIRKS */ }; @@ -253,8 +246,6 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct conexant_spec *spec = codec->spec; - if (spec->capture_prepare) - spec->capture_prepare(codec); snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], stream_tag, 0, format); return 0; @@ -266,8 +257,6 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, { struct conexant_spec *spec = codec->spec; snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - if (spec->capture_cleanup) - spec->capture_cleanup(codec); return 0; } @@ -673,14 +662,6 @@ static const struct hda_input_mux cxt5045_capture_source_benq = { } }; -static const struct hda_input_mux cxt5045_capture_source_hp530 = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Internal Mic", 0x2 }, - } -}; - /* turn on/off EAPD (+ mute HP) as a master switch */ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -796,28 +777,6 @@ static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { {} }; -static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT), - HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5045_hp_master_sw_put, - .private_value = 0x10, - }, - - {} -}; - static const struct hda_verb cxt5045_init_verbs[] = { /* Line in, Mic */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, @@ -1000,7 +959,6 @@ enum { CXT5045_LAPTOP_MICSENSE, CXT5045_LAPTOP_HPMICSENSE, CXT5045_BENQ, - CXT5045_LAPTOP_HP530, #ifdef CONFIG_SND_DEBUG CXT5045_TEST, #endif @@ -1013,7 +971,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = { [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", [CXT5045_BENQ] = "benq", - [CXT5045_LAPTOP_HP530] = "laptop-hp530", #ifdef CONFIG_SND_DEBUG [CXT5045_TEST] = "test", #endif @@ -1021,8 +978,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = { }; static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE), SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), @@ -1113,14 +1068,6 @@ static int patch_cxt5045(struct hda_codec *codec) spec->num_mixers = 2; codec->patch_ops.init = cxt5045_init; break; - case CXT5045_LAPTOP_HP530: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source_hp530; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers_hp530; - codec->patch_ops.init = cxt5045_init; - break; #ifdef CONFIG_SND_DEBUG case CXT5045_TEST: spec->input_mux = &cxt5045_test_capture_source; @@ -1940,11 +1887,6 @@ static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; -/* OLPC's microphone port is DC coupled for use with external sensors, - * therefore we use a 50% mic bias in order to center the input signal with - * the DC input range of the codec. */ -#define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 - static const struct hda_channel_mode cxt5066_modes[1] = { { 2, NULL }, }; @@ -1997,88 +1939,6 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct hda_input_mux cxt5066_olpc_dc_bias = { - .num_items = 3, - .items = { - { "Off", PIN_IN }, - { "50%", PIN_VREF50 }, - { "80%", PIN_VREF80 }, - }, -}; - -static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - /* Even though port F is the DC input, the bias is controlled on port B. - * we also leave that port as an active input (but unselected) in DC mode - * just in case that is necessary to make the bias setting take effect. */ - return snd_hda_set_pin_ctl_cache(codec, 0x1a, - cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); -} - -/* OLPC defers mic widget control until when capture is started because the - * microphone LED comes on as soon as these settings are put in place. if we - * did this before recording, it would give the false indication that recording - * is happening when it is not. */ -static void cxt5066_olpc_select_mic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - if (!spec->recording) - return; - - if (spec->dc_enable) { - /* in DC mode we ignore presence detection and just use the jack - * through our special DC port */ - const struct hda_verb enable_dc_mode[] = { - /* disble internal mic, port C */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* enable DC capture, port F */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {}, - }; - - snd_hda_sequence_write(codec, enable_dc_mode); - /* port B input disabled (and bias set) through the following call */ - cxt5066_set_olpc_dc_bias(codec); - return; - } - - /* disable DC (port F) */ - snd_hda_set_pin_ctl(codec, 0x1e, 0); - - /* external mic, port B */ - snd_hda_set_pin_ctl(codec, 0x1a, - spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); - - /* internal mic, port C */ - snd_hda_set_pin_ctl(codec, 0x1b, - spec->ext_mic_present ? 0 : PIN_VREF80); -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5066_olpc_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int present; - - if (spec->dc_enable) /* don't do presence detection in DC mode */ - return; - - present = snd_hda_codec_read(codec, 0x1a, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - if (present) - snd_printdd("CXT5066: external microphone detected\n"); - else - snd_printdd("CXT5066: external microphone absent\n"); - - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, - present ? 0 : 1); - spec->ext_mic_present = !!present; - - cxt5066_olpc_select_mic(codec); -} - /* toggle input of built-in digital mic and mic jack appropriately */ static void cxt5066_vostro_automic(struct hda_codec *codec) { @@ -2252,23 +2112,6 @@ static void cxt5066_automic(struct hda_codec *codec) } /* unsolicited event for jack sensing */ -static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) -{ - struct conexant_spec *spec = codec->spec; - snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5066_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - /* ignore mic events in DC mode; we're always using the jack */ - if (!spec->dc_enable) - cxt5066_olpc_automic(codec); - break; - } -} - -/* unsolicited event for jack sensing */ static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) { snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); @@ -2338,124 +2181,10 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, idx = imux->num_items - 1; spec->mic_boost = idx; - if (!spec->dc_enable) - cxt5066_set_mic_boost(codec); - return 1; -} - -static void cxt5066_enable_dc(struct hda_codec *codec) -{ - const struct hda_verb enable_dc_mode[] = { - /* disable gain */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* switch to DC input */ - {0x17, AC_VERB_SET_CONNECT_SEL, 3}, - {} - }; - - /* configure as input source */ - snd_hda_sequence_write(codec, enable_dc_mode); - cxt5066_olpc_select_mic(codec); /* also sets configured bias */ -} - -static void cxt5066_disable_dc(struct hda_codec *codec) -{ - /* reconfigure input source */ cxt5066_set_mic_boost(codec); - /* automic also selects the right mic if we're recording */ - cxt5066_olpc_automic(codec); -} - -static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - ucontrol->value.integer.value[0] = spec->dc_enable; - return 0; -} - -static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int dc_enable = !!ucontrol->value.integer.value[0]; - - if (dc_enable == spec->dc_enable) - return 0; - - spec->dc_enable = dc_enable; - if (dc_enable) - cxt5066_enable_dc(codec); - else - cxt5066_disable_dc(codec); - - return 1; -} - -static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo); -} - -static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->dc_input_bias; - return 0; -} - -static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; - unsigned int idx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - - spec->dc_input_bias = idx; - if (spec->dc_enable) - cxt5066_set_olpc_dc_bias(codec); return 1; } -static void cxt5066_olpc_capture_prepare(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - /* mark as recording and configure the microphone widget so that the - * recording LED comes on. */ - spec->recording = 1; - cxt5066_olpc_select_mic(codec); -} - -static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - const struct hda_verb disable_mics[] = { - /* disable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* disble internal mic, port C */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* disable DC capture, port F */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {}, - }; - - snd_hda_sequence_write(codec, disable_mics); - spec->recording = 0; -} - static void conexant_check_dig_outs(struct hda_codec *codec, const hda_nid_t *dig_pins, int num_pins) @@ -2506,43 +2235,6 @@ static const struct snd_kcontrol_new cxt5066_mixer_master[] = { {} }; -static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = snd_hda_mixer_amp_volume_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - /* offset by 28 volume steps to limit minimum gain to -46dB */ - .private_value = - HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28), - }, - {} -}; - -static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "DC Mode Enable Switch", - .info = snd_ctl_boolean_mono_info, - .get = cxt5066_olpc_dc_get, - .put = cxt5066_olpc_dc_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "DC Input Bias Enum", - .info = cxt5066_olpc_dc_bias_enum_info, - .get = cxt5066_olpc_dc_bias_enum_get, - .put = cxt5066_olpc_dc_bias_enum_put, - }, - {} -}; - static const struct snd_kcontrol_new cxt5066_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -2633,67 +2325,6 @@ static const struct hda_verb cxt5066_init_verbs[] = { { } /* end */ }; -static const struct hda_verb cxt5066_init_verbs_olpc[] = { - /* Port A: headphones */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port B: external microphone */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port C: internal microphone */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port D: unused */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port E: unused, but has primary EAPD */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* Port F: external DC input through microphone port */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port G: internal speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* DAC2: unused */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - - /* Disable digital microphone port */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Audio input selectors */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - - /* Disable SPDIF */ - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* enable unsolicited events for Port A and B */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - static const struct hda_verb cxt5066_init_verbs_vostro[] = { /* Port A: headphones */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, @@ -2889,25 +2520,9 @@ static int cxt5066_init(struct hda_codec *codec) return 0; } -static int cxt5066_olpc_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - snd_printdd("CXT5066: init\n"); - conexant_init(codec); - cxt5066_hp_automute(codec); - if (!spec->dc_enable) { - cxt5066_set_mic_boost(codec); - cxt5066_olpc_automic(codec); - } else { - cxt5066_enable_dc(codec); - } - return 0; -} - enum { CXT5066_LAPTOP, /* Laptops w/ EAPD support */ CXT5066_DELL_LAPTOP, /* Dell Laptop */ - CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ @@ -2920,7 +2535,6 @@ enum { static const char * const cxt5066_models[CXT5066_MODELS] = { [CXT5066_LAPTOP] = "laptop", [CXT5066_DELL_LAPTOP] = "dell-laptop", - [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", [CXT5066_DELL_VOSTRO] = "dell-vostro", [CXT5066_IDEAPAD] = "ideapad", [CXT5066_THINKPAD] = "thinkpad", @@ -2941,10 +2555,8 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS), SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS), SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", CXT5066_LAPTOP), - SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), @@ -3030,32 +2642,11 @@ static int patch_cxt5066(struct hda_codec *codec) spec->mic_boost = 3; /* default 30dB gain */ break; - case CXT5066_OLPC_XO_1_5: - codec->patch_ops.init = cxt5066_olpc_init; - codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; - spec->init_verbs[0] = cxt5066_init_verbs_olpc; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->port_d_mode = 0; - spec->mic_boost = 3; /* default 30dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - - /* our capture hooks which allow us to turn on the microphone LED - * at the right time */ - spec->capture_prepare = cxt5066_olpc_capture_prepare; - spec->capture_cleanup = cxt5066_olpc_capture_cleanup; - break; case CXT5066_DELL_VOSTRO: codec->patch_ops.init = cxt5066_init; codec->patch_ops.unsol_event = cxt5066_unsol_event; spec->init_verbs[0] = cxt5066_init_verbs_vostro; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; spec->mixers[spec->num_mixers++] = cxt5066_mixers; spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; spec->port_d_mode = 0; @@ -3207,11 +2798,7 @@ static int cx_auto_init(struct hda_codec *codec) return 0; } -static void cx_auto_free(struct hda_codec *codec) -{ - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE); - snd_hda_gen_free(codec); -} +#define cx_auto_free snd_hda_gen_free static const struct hda_codec_ops cx_auto_patch_ops = { .build_controls = cx_auto_build_controls, @@ -3238,6 +2825,11 @@ enum { CXT_FIXUP_HEADPHONE_MIC, CXT_FIXUP_GPIO1, CXT_FIXUP_THINKPAD_ACPI, + CXT_FIXUP_OLPC_XO, + CXT_FIXUP_CAP_MIX_AMP, + CXT_FIXUP_TOSHIBA_P105, + CXT_FIXUP_HP_530, + CXT_FIXUP_CAP_MIX_AMP_5047, }; /* for hda_fixup_thinkpad_acpi() */ @@ -3316,6 +2908,288 @@ static void cxt_fixup_headphone_mic(struct hda_codec *codec, } } +/* OPLC XO 1.5 fixup */ + +/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) + * through the microphone jack. + * When the user enables this through a mixer switch, both internal and + * external microphones are disabled. Gain is fixed at 0dB. In this mode, + * we also allow the bias to be configured through a separate mixer + * control. */ + +#define update_mic_pin(codec, nid, val) \ + snd_hda_codec_update_cache(codec, nid, 0, \ + AC_VERB_SET_PIN_WIDGET_CONTROL, val) + +static const struct hda_input_mux olpc_xo_dc_bias = { + .num_items = 3, + .items = { + { "Off", PIN_IN }, + { "50%", PIN_VREF50 }, + { "80%", PIN_VREF80 }, + }, +}; + +static void olpc_xo_update_mic_boost(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + int ch, val; + + for (ch = 0; ch < 2; ch++) { + val = AC_AMP_SET_OUTPUT | + (ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT); + if (!spec->dc_enable) + val |= snd_hda_codec_amp_read(codec, 0x17, ch, HDA_OUTPUT, 0); + snd_hda_codec_write(codec, 0x17, 0, + AC_VERB_SET_AMP_GAIN_MUTE, val); + } +} + +static void olpc_xo_update_mic_pins(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + int cur_input, val; + struct nid_path *path; + + cur_input = spec->gen.input_paths[0][spec->gen.cur_mux[0]]; + + /* Set up mic pins for port-B, C and F dynamically as the recording + * LED is turned on/off by these pin controls + */ + if (!spec->dc_enable) { + /* disable DC bias path and pin for port F */ + update_mic_pin(codec, 0x1e, 0); + snd_hda_activate_path(codec, spec->dc_mode_path, false, false); + + /* update port B (ext mic) and C (int mic) */ + /* OLPC defers mic widget control until when capture is + * started because the microphone LED comes on as soon as + * these settings are put in place. if we did this before + * recording, it would give the false indication that + * recording is happening when it is not. + */ + update_mic_pin(codec, 0x1a, spec->recording ? + snd_hda_codec_get_pin_target(codec, 0x1a) : 0); + update_mic_pin(codec, 0x1b, spec->recording ? + snd_hda_codec_get_pin_target(codec, 0x1b) : 0); + /* enable normal mic path */ + path = snd_hda_get_path_from_idx(codec, cur_input); + if (path) + snd_hda_activate_path(codec, path, true, false); + } else { + /* disable normal mic path */ + path = snd_hda_get_path_from_idx(codec, cur_input); + if (path) + snd_hda_activate_path(codec, path, false, false); + + /* Even though port F is the DC input, the bias is controlled + * on port B. We also leave that port as an active input (but + * unselected) in DC mode just in case that is necessary to + * make the bias setting take effect. + */ + if (spec->recording) + val = olpc_xo_dc_bias.items[spec->dc_input_bias].index; + else + val = 0; + update_mic_pin(codec, 0x1a, val); + update_mic_pin(codec, 0x1b, 0); + /* enable DC bias path and pin */ + update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0); + snd_hda_activate_path(codec, spec->dc_mode_path, true, false); + } +} + +/* mic_autoswitch hook */ +static void olpc_xo_automic(struct hda_codec *codec, struct hda_jack_tbl *jack) +{ + struct conexant_spec *spec = codec->spec; + int saved_cached_write = codec->cached_write; + + codec->cached_write = 1; + /* in DC mode, we don't handle automic */ + if (!spec->dc_enable) + snd_hda_gen_mic_autoswitch(codec, jack); + olpc_xo_update_mic_pins(codec); + snd_hda_codec_flush_cache(codec); + codec->cached_write = saved_cached_write; + if (spec->dc_enable) + olpc_xo_update_mic_boost(codec); +} + +/* pcm_capture hook */ +static void olpc_xo_capture_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + struct conexant_spec *spec = codec->spec; + + /* toggle spec->recording flag and update mic pins accordingly + * for turning on/off LED + */ + switch (action) { + case HDA_GEN_PCM_ACT_PREPARE: + spec->recording = 1; + olpc_xo_update_mic_pins(codec); + break; + case HDA_GEN_PCM_ACT_CLEANUP: + spec->recording = 0; + olpc_xo_update_mic_pins(codec); + break; + } +} + +static int olpc_xo_dc_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + ucontrol->value.integer.value[0] = spec->dc_enable; + return 0; +} + +static int olpc_xo_dc_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + int dc_enable = !!ucontrol->value.integer.value[0]; + + if (dc_enable == spec->dc_enable) + return 0; + + spec->dc_enable = dc_enable; + olpc_xo_update_mic_pins(codec); + olpc_xo_update_mic_boost(codec); + return 1; +} + +static int olpc_xo_dc_bias_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = spec->dc_input_bias; + return 0; +} + +static int olpc_xo_dc_bias_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + return snd_hda_input_mux_info(&olpc_xo_dc_bias, uinfo); +} + +static int olpc_xo_dc_bias_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + const struct hda_input_mux *imux = &olpc_xo_dc_bias; + unsigned int idx; + + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (spec->dc_input_bias == idx) + return 0; + + spec->dc_input_bias = idx; + if (spec->dc_enable) + olpc_xo_update_mic_pins(codec); + return 1; +} + +static const struct snd_kcontrol_new olpc_xo_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DC Mode Enable Switch", + .info = snd_ctl_boolean_mono_info, + .get = olpc_xo_dc_mode_get, + .put = olpc_xo_dc_mode_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DC Input Bias Enum", + .info = olpc_xo_dc_bias_enum_info, + .get = olpc_xo_dc_bias_enum_get, + .put = olpc_xo_dc_bias_enum_put, + }, + {} +}; + +/* overriding mic boost put callback; update mic boost volume only when + * DC mode is disabled + */ +static int olpc_xo_mic_boost_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + int ret = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); + if (ret > 0 && spec->dc_enable) + olpc_xo_update_mic_boost(codec); + return ret; +} + +static void cxt_fixup_olpc_xo(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct conexant_spec *spec = codec->spec; + int i; + + if (action != HDA_FIXUP_ACT_PROBE) + return; + + spec->gen.mic_autoswitch_hook = olpc_xo_automic; + spec->gen.pcm_capture_hook = olpc_xo_capture_hook; + spec->dc_mode_path = snd_hda_add_new_path(codec, 0x1e, 0x14, 0); + + snd_hda_add_new_ctls(codec, olpc_xo_mixers); + + /* OLPC's microphone port is DC coupled for use with external sensors, + * therefore we use a 50% mic bias in order to center the input signal + * with the DC input range of the codec. + */ + snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50); + + /* override mic boost control */ + for (i = 0; i < spec->gen.kctls.used; i++) { + struct snd_kcontrol_new *kctl = + snd_array_elem(&spec->gen.kctls, i); + if (!strcmp(kctl->name, "Mic Boost Volume")) { + kctl->put = olpc_xo_mic_boost_put; + break; + } + } +} + +/* + * Fix max input level on mixer widget to 0dB + * (originally it has 0x2b steps with 0dB offset 0x14) + */ +static void cxt_fixup_cap_mix_amp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, + (0x14 << AC_AMPCAP_OFFSET_SHIFT) | + (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); +} + +/* + * Fix max input level on mixer widget to 0dB + * (originally it has 0x1e steps with 0 dB offset 0x17) + */ +static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); +} /* ThinkPad X200 & co with cxt5051 */ static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { @@ -3401,6 +3275,68 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = hda_fixup_thinkpad_acpi, }, + [CXT_FIXUP_OLPC_XO] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_olpc_xo, + }, + [CXT_FIXUP_CAP_MIX_AMP] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_cap_mix_amp, + }, + [CXT_FIXUP_TOSHIBA_P105] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x10, 0x961701f0 }, /* speaker/hp */ + { 0x12, 0x02a1901e }, /* ext mic */ + { 0x14, 0x95a70110 }, /* int mic */ + {} + }, + }, + [CXT_FIXUP_HP_530] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x12, 0x90a60160 }, /* int mic */ + {} + }, + .chained = true, + .chain_id = CXT_FIXUP_CAP_MIX_AMP, + }, + [CXT_FIXUP_CAP_MIX_AMP_5047] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_cap_mix_amp_5047, + }, +}; + +static const struct snd_pci_quirk cxt5045_fixups[] = { + SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530), + SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105), + /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have + * really bad sound over 0dB on NID 0x17. + */ + SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP), + SND_PCI_QUIRK_VENDOR(0x1631, "Packard Bell", CXT_FIXUP_CAP_MIX_AMP), + SND_PCI_QUIRK_VENDOR(0x1734, "Fujitsu", CXT_FIXUP_CAP_MIX_AMP), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT_FIXUP_CAP_MIX_AMP), + {} +}; + +static const struct hda_model_fixup cxt5045_fixup_models[] = { + { .id = CXT_FIXUP_CAP_MIX_AMP, .name = "cap-mix-amp" }, + { .id = CXT_FIXUP_TOSHIBA_P105, .name = "toshiba-p105" }, + { .id = CXT_FIXUP_HP_530, .name = "hp-530" }, + {} +}; + +static const struct snd_pci_quirk cxt5047_fixups[] = { + /* HP laptops have really bad sound over 0 dB on NID 0x10. + */ + SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047), + {} +}; + +static const struct hda_model_fixup cxt5047_fixup_models[] = { + { .id = CXT_FIXUP_CAP_MIX_AMP_5047, .name = "cap-mix-amp" }, + {} }; static const struct snd_pci_quirk cxt5051_fixups[] = { @@ -3408,10 +3344,16 @@ static const struct snd_pci_quirk cxt5051_fixups[] = { {} }; +static const struct hda_model_fixup cxt5051_fixup_models[] = { + { .id = CXT_PINCFG_LENOVO_X200, .name = "lenovo-x200" }, + {} +}; + static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), + SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), @@ -3428,6 +3370,17 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { {} }; +static const struct hda_model_fixup cxt5066_fixup_models[] = { + { .id = CXT_FIXUP_STEREO_DMIC, .name = "stereo-dmic" }, + { .id = CXT_FIXUP_GPIO1, .name = "gpio1" }, + { .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" }, + { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" }, + { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" }, + { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" }, + { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, + {} +}; + /* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches * can be created (bko#42825) */ @@ -3467,19 +3420,28 @@ static int patch_conexant_auto(struct hda_codec *codec) switch (codec->vendor_id) { case 0x14f15045: codec->single_adc_amp = 1; + spec->gen.mixer_nid = 0x17; + spec->gen.add_stereo_mix_input = 1; + snd_hda_pick_fixup(codec, cxt5045_fixup_models, + cxt5045_fixups, cxt_fixups); break; case 0x14f15047: codec->pin_amp_workaround = 1; spec->gen.mixer_nid = 0x19; + spec->gen.add_stereo_mix_input = 1; + snd_hda_pick_fixup(codec, cxt5047_fixup_models, + cxt5047_fixups, cxt_fixups); break; case 0x14f15051: add_cx5051_fake_mutes(codec); codec->pin_amp_workaround = 1; - snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups); + snd_hda_pick_fixup(codec, cxt5051_fixup_models, + cxt5051_fixups, cxt_fixups); break; default: codec->pin_amp_workaround = 1; - snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups); + snd_hda_pick_fixup(codec, cxt5066_fixup_models, + cxt5066_fixups, cxt_fixups); break; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0ab0b9e..86857b6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -845,11 +845,7 @@ static inline void alc_shutup(struct hda_codec *codec) snd_hda_shutup_pins(codec); } -static void alc_free(struct hda_codec *codec) -{ - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE); - snd_hda_gen_free(codec); -} +#define alc_free snd_hda_gen_free #ifdef CONFIG_PM static void alc_power_eapd(struct hda_codec *codec) @@ -4875,8 +4871,42 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec, } } +/* turn on/off mute LED per vmaster hook */ +static void alc662_led_gpio1_mute_hook(void *private_data, int enabled) +{ + struct hda_codec *codec = private_data; + struct alc_spec *spec = codec->spec; + unsigned int oldval = spec->gpio_led; + + if (enabled) + spec->gpio_led &= ~0x01; + else + spec->gpio_led |= 0x01; + if (spec->gpio_led != oldval) + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_led); +} + +static void alc662_fixup_led_gpio1(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 }, + {} + }; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = alc662_led_gpio1_mute_hook; + spec->gpio_led = 0; + snd_hda_add_verbs(codec, gpio_init); + } +} + enum { ALC662_FIXUP_ASPIRE, + ALC662_FIXUP_LED_GPIO1, ALC662_FIXUP_IDEAPAD, ALC272_FIXUP_MARIO, ALC662_FIXUP_CZC_P10T, @@ -4895,9 +4925,10 @@ enum { ALC662_FIXUP_INV_DMIC, ALC668_FIXUP_DELL_MIC_NO_PRESENCE, ALC668_FIXUP_HEADSET_MODE, - ALC662_FIXUP_BASS_CHMAP, + ALC662_FIXUP_BASS_MODE4_CHMAP, + ALC662_FIXUP_BASS_16, ALC662_FIXUP_BASS_1A, - ALC662_FIXUP_BASS_1A_CHMAP, + ALC662_FIXUP_BASS_CHMAP, ALC668_FIXUP_AUTO_MUTE, }; @@ -4909,12 +4940,18 @@ static const struct hda_fixup alc662_fixups[] = { { } } }, + [ALC662_FIXUP_LED_GPIO1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc662_fixup_led_gpio1, + }, [ALC662_FIXUP_IDEAPAD] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { { 0x17, 0x99130112 }, /* subwoofer */ { } - } + }, + .chained = true, + .chain_id = ALC662_FIXUP_LED_GPIO1, }, [ALC272_FIXUP_MARIO] = { .type = HDA_FIXUP_FUNC, @@ -5079,24 +5116,33 @@ static const struct hda_fixup alc662_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode_alc668, }, - [ALC662_FIXUP_BASS_CHMAP] = { + [ALC662_FIXUP_BASS_MODE4_CHMAP] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_bass_chmap, .chained = true, .chain_id = ALC662_FIXUP_ASUS_MODE4 }, + [ALC662_FIXUP_BASS_16] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + {0x16, 0x80106111}, /* bass speaker */ + {} + }, + .chained = true, + .chain_id = ALC662_FIXUP_BASS_CHMAP, + }, [ALC662_FIXUP_BASS_1A] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { {0x1a, 0x80106111}, /* bass speaker */ {} }, + .chained = true, + .chain_id = ALC662_FIXUP_BASS_CHMAP, }, - [ALC662_FIXUP_BASS_1A_CHMAP] = { + [ALC662_FIXUP_BASS_CHMAP] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_bass_chmap, - .chained = true, - .chain_id = ALC662_FIXUP_BASS_1A, }, }; @@ -5118,9 +5164,11 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE), SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), - SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A_CHMAP), - SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_CHMAP), - SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_CHMAP), + SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A), + SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), + SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), + SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16), + SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index f84195f..7781662 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -465,14 +465,8 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, static void via_free(struct hda_codec *codec) { - struct via_spec *spec = codec->spec; - - if (!spec) - return; - vt1708_stop_hp_work(codec); - snd_hda_gen_spec_free(&spec->gen); - kfree(spec); + snd_hda_gen_free(codec); } #ifdef CONFIG_PM diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index 626ecad..df4044d 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -141,63 +141,6 @@ void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data) iowrite32(data, address); } -u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr) -{ - int index; - - switch (mbox_nr) { - case 1: - index = ePLX_MBOX1; break; - case 2: - index = ePLX_MBOX2; break; - case 3: - index = ePLX_MBOX3; break; - case 4: - index = ePLX_MBOX4; break; - case 5: - index = ePLX_MBOX5; break; - case 6: - index = ePLX_MBOX6; break; - case 7: - index = ePLX_MBOX7; break; - case 0: /* reserved for HF flags */ - snd_BUG(); - default: - return 0xdeadbeef; - } - - return lx_plx_reg_read(chip, index); -} - -int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value) -{ - int index = -1; - - switch (mbox_nr) { - case 1: - index = ePLX_MBOX1; break; - case 3: - index = ePLX_MBOX3; break; - case 4: - index = ePLX_MBOX4; break; - case 5: - index = ePLX_MBOX5; break; - case 6: - index = ePLX_MBOX6; break; - case 7: - index = ePLX_MBOX7; break; - case 0: /* reserved for HF flags */ - case 2: /* reserved for Pipe States - * the DSP keeps an image of it */ - snd_BUG(); - return -EBADRQC; - } - - lx_plx_reg_write(chip, index, value); - return 0; -} - - /* rmh */ #ifdef CONFIG_SND_DEBUG @@ -491,33 +434,6 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) #define CSES_BROADCAST 0x0002 #define CSES_UPDATE_LDSV 0x0004 -int lx_dsp_es_check_pipeline(struct lx6464es *chip) -{ - int i; - - for (i = 0; i != CSES_TIMEOUT; ++i) { - /* - * le bit CSES_UPDATE_LDSV est à 1 dés que le macprog - * est pret. il re-passe à 0 lorsque le premier read a - * été fait. pour l'instant on retire le test car ce bit - * passe a 1 environ 200 à 400 ms aprés que le registre - * confES à été écrit (kick du xilinx ES). - * - * On ne teste que le bit CE. - * */ - - u32 cses = lx_dsp_reg_read(chip, eReg_CSES); - - if ((cses & CSES_CE) == 0) - return 0; - - udelay(1); - } - - return -ETIMEDOUT; -} - - #define PIPE_INFO_TO_CMD(capture, pipe) \ ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET) diff --git a/sound/usb/card.c b/sound/usb/card.c index d979050..0252241 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -691,12 +691,12 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) } list_for_each_entry(mixer, &chip->mixer_list, list) - snd_usb_mixer_inactivate(mixer); + snd_usb_mixer_suspend(mixer); return 0; } -static int usb_audio_resume(struct usb_interface *intf) +static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) { struct snd_usb_audio *chip = usb_get_intfdata(intf); struct usb_mixer_interface *mixer; @@ -711,7 +711,7 @@ static int usb_audio_resume(struct usb_interface *intf) * we just notify and restart the mixers */ list_for_each_entry(mixer, &chip->mixer_list, list) { - err = snd_usb_mixer_activate(mixer); + err = snd_usb_mixer_resume(mixer, reset_resume); if (err < 0) goto err_out; } @@ -723,9 +723,20 @@ static int usb_audio_resume(struct usb_interface *intf) err_out: return err; } + +static int usb_audio_resume(struct usb_interface *intf) +{ + return __usb_audio_resume(intf, false); +} + +static int usb_audio_reset_resume(struct usb_interface *intf) +{ + return __usb_audio_resume(intf, true); +} #else #define usb_audio_suspend NULL #define usb_audio_resume NULL +#define usb_audio_reset_resume NULL #endif /* CONFIG_PM */ static struct usb_device_id usb_audio_ids [] = { @@ -747,6 +758,7 @@ static struct usb_driver usb_audio_driver = { .disconnect = usb_audio_disconnect, .suspend = usb_audio_suspend, .resume = usb_audio_resume, + .reset_resume = usb_audio_reset_resume, .id_table = usb_audio_ids, .supports_autosuspend = 1, }; diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 44b0ba4..aa9bc19 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2299,26 +2299,6 @@ requeue: } } -/* stop any bus activity of a mixer */ -void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer) -{ - usb_kill_urb(mixer->urb); - usb_kill_urb(mixer->rc_urb); -} - -int snd_usb_mixer_activate(struct usb_mixer_interface *mixer) -{ - int err; - - if (mixer->urb) { - err = usb_submit_urb(mixer->urb, GFP_NOIO); - if (err < 0) - return err; - } - - return 0; -} - /* create the handler for the optional status interrupt endpoint */ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) { @@ -2417,3 +2397,82 @@ void snd_usb_mixer_disconnect(struct list_head *p) usb_kill_urb(mixer->urb); usb_kill_urb(mixer->rc_urb); } + +#ifdef CONFIG_PM +/* stop any bus activity of a mixer */ +static void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer) +{ + usb_kill_urb(mixer->urb); + usb_kill_urb(mixer->rc_urb); +} + +static int snd_usb_mixer_activate(struct usb_mixer_interface *mixer) +{ + int err; + + if (mixer->urb) { + err = usb_submit_urb(mixer->urb, GFP_NOIO); + if (err < 0) + return err; + } + + return 0; +} + +int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer) +{ + snd_usb_mixer_inactivate(mixer); + return 0; +} + +static int restore_mixer_value(struct usb_mixer_elem_info *cval) +{ + int c, err, idx; + + if (cval->cmask) { + idx = 0; + for (c = 0; c < MAX_CHANNELS; c++) { + if (!(cval->cmask & (1 << c))) + continue; + if (cval->cached & (1 << c)) { + err = set_cur_mix_value(cval, c + 1, idx, + cval->cache_val[idx]); + if (err < 0) + return err; + } + idx++; + } + } else { + /* master */ + if (cval->cached) { + err = set_cur_mix_value(cval, 0, 0, *cval->cache_val); + if (err < 0) + return err; + } + } + + return 0; +} + +int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) +{ + struct usb_mixer_elem_info *cval; + int id, err; + + /* FIXME: any mixer quirks? */ + + if (reset_resume) { + /* restore cached mixer values */ + for (id = 0; id < MAX_ID_ELEMS; id++) { + for (cval = mixer->id_elems[id]; cval; + cval = cval->next_id_elem) { + err = restore_mixer_value(cval); + if (err < 0) + return err; + } + } + } + + return snd_usb_mixer_activate(mixer); +} +#endif diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index aab80df..73b1f64 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -63,8 +63,6 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid); int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int value_set); -void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer); -int snd_usb_mixer_activate(struct usb_mixer_interface *mixer); int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, struct snd_kcontrol *kctl); @@ -72,4 +70,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv); +#ifdef CONFIG_PM +int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer); +int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume); +#endif + #endif /* __USBMIXER_H */ |