static void cxt_update_headset_mode(struct hda_codec *codec) { /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */ int i; bool mic_mode = false; struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->gen.autocfg; hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; for (i = 0; i < cfg->num_inputs; i++) if (cfg->inputs[i].pin == mux_pin) { mic_mode = !!cfg->inputs[i].is_headphone_mic; break; } if (mic_mode) { snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */ spec->gen.hp_jack_present = false; } else { snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */ spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]); } snd_hda_gen_update_outputs(codec); }
/** * snd_hda_jack_detect_enable - enable the jack-detection * * In the case of error, the return value will be a pointer embedded with * errno. Check and handle the return value appropriately with standard * macros such as @IS_ERR() and @PTR_ERR(). */ struct hda_jack_callback * snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, hda_jack_callback_fn func) { struct hda_jack_tbl *jack; struct hda_jack_callback *callback = NULL; int err; jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) return ERR_PTR(-ENOMEM); if (func) { callback = kzalloc(sizeof(*callback), GFP_KERNEL); if (!callback) return ERR_PTR(-ENOMEM); callback->func = func; callback->tbl = jack; callback->next = jack->callback; jack->callback = callback; } if (jack->jack_detect) return callback; /* already registered */ jack->jack_detect = 1; if (codec->jackpoll_interval > 0) return callback; /* No unsol if we're polling instead */ err = snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | jack->tag); if (err < 0) return ERR_PTR(err); return callback; }
static void cs_automic(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid; unsigned int present; nid = cfg->inputs[spec->automic_idx].pin; present = snd_hda_jack_detect(codec, nid); /* specific to CS421x, single ADC */ if (spec->vendor_nid == CS421X_VENDOR_NID) { if (present) { spec->last_input = spec->cur_input; spec->cur_input = spec->automic_idx; } else { spec->cur_input = spec->last_input; } snd_hda_codec_write_cache(codec, spec->cur_adc, 0, AC_VERB_SET_CONNECT_SEL, spec->adc_idx[spec->cur_input]); } else { if (present) change_cur_input(codec, spec->automic_idx, 0); else change_cur_input(codec, !spec->automic_idx, 0); } }
/** * snd_hda_attach_beep_device - Attach a beep input device * @codec: the HDA codec * @nid: beep NID * * Attach a beep object to the given widget. If beep hint is turned off * explicitly or beep_mode of the codec is turned off, this doesn't nothing. * * The attached beep device has to be registered via * snd_hda_register_beep_device() and released via snd_hda_detach_beep_device() * appropriately. * * Currently, only one beep device is allowed to each codec. */ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) { struct hda_beep *beep; int err; if (!snd_hda_get_bool_hint(codec, "beep")) return 0; /* disabled explicitly by hints */ if (codec->beep_mode == HDA_BEEP_MODE_OFF) return 0; /* disabled by module option */ beep = kzalloc(sizeof(*beep), GFP_KERNEL); if (beep == NULL) return -ENOMEM; snprintf(beep->phys, sizeof(beep->phys), "card%d/codec#%d/beep0", codec->card->number, codec->addr); /* enable linear scale */ snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, 0x01); beep->nid = nid; beep->codec = codec; codec->beep = beep; INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); mutex_init(&beep->mutex); err = snd_hda_do_attach(beep); if (err < 0) { kfree(beep); codec->beep = NULL; return err; } return 0; }
/* follow EAPD via vmaster hook */ static void ad_vmaster_eapd_hook(void *private_data, int enabled) { struct hda_codec *codec = private_data; struct ad198x_spec *spec = codec->spec; if (!spec->eapd_nid) return; if (codec->inv_eapd) enabled = !enabled; snd_hda_codec_write_cache(codec, spec->eapd_nid, 0, AC_VERB_SET_EAPD_BTLENABLE, enabled ? 0x02 : 0x00); }
/** * snd_hda_jack_detect_enable - enable the jack-detection */ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, unsigned char action) { struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) return -ENOMEM; if (jack->jack_detect) return 0; /* already registered */ jack->jack_detect = 1; if (action) jack->action = action; return snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | jack->tag); }
static int ad1983_auto_smux_enum_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 val = ucontrol->value.enumerated.item[0]; hda_nid_t dig_out = spec->gen.multiout.dig_out_nid; int num_conns = snd_hda_get_num_conns(codec, dig_out); if (val >= num_conns) return -EINVAL; if (spec->cur_smux == val) return 0; spec->cur_smux = val; snd_hda_codec_write_cache(codec, dig_out, 0, AC_VERB_SET_CONNECT_SEL, val); return 1; }
static int ad198x_eapd_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; hda_nid_t nid = kcontrol->private_value & 0xff; unsigned int eapd; eapd = !!ucontrol->value.integer.value[0]; if (codec->inv_eapd) eapd = !eapd; if (eapd == spec->cur_eapd) return 0; spec->cur_eapd = eapd; snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, eapd ? 0x02 : 0x00); return 1; }
/** * snd_hda_jack_detect_enable - enable the jack-detection */ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, unsigned char action, hda_jack_callback cb) { struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) return -ENOMEM; if (jack->jack_detect) return 0; /* already registered */ jack->jack_detect = 1; if (action) jack->action = action; if (cb) jack->callback = cb; if (codec->jackpoll_interval > 0) return 0; /* No unsol if we're polling instead */ return snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | jack->tag); }
/** * snd_hda_attach_beep_device - Attach a beep input device * @codec: the HDA codec * @nid: beep NID * * Attach a beep object to the given widget. If beep hint is turned off * explicitly or beep_mode of the codec is turned off, this doesn't nothing. * * Currently, only one beep device is allowed to each codec. */ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) { static struct snd_device_ops ops = { .dev_register = beep_dev_register, .dev_disconnect = beep_dev_disconnect, .dev_free = beep_dev_free, }; struct input_dev *input_dev; struct hda_beep *beep; int err; if (!snd_hda_get_bool_hint(codec, "beep")) return 0; /* disabled explicitly by hints */ if (codec->beep_mode == HDA_BEEP_MODE_OFF) return 0; /* disabled by module option */ beep = kzalloc(sizeof(*beep), GFP_KERNEL); if (beep == NULL) return -ENOMEM; snprintf(beep->phys, sizeof(beep->phys), "card%d/codec#%d/beep0", codec->card->number, codec->addr); /* enable linear scale */ snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, 0x01); beep->nid = nid; beep->codec = codec; codec->beep = beep; INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); mutex_init(&beep->mutex); input_dev = input_allocate_device(); if (!input_dev) { err = -ENOMEM; goto err_free; } /* setup digital beep device */ input_dev->name = "HDA Digital PCBeep"; input_dev->phys = beep->phys; input_dev->id.bustype = BUS_PCI; input_dev->dev.parent = &codec->card->card_dev; input_dev->id.vendor = codec->core.vendor_id >> 16; input_dev->id.product = codec->core.vendor_id & 0xffff; input_dev->id.version = 0x01; input_dev->evbit[0] = BIT_MASK(EV_SND); input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); input_dev->event = snd_hda_beep_event; input_set_drvdata(input_dev, beep); beep->dev = input_dev; err = snd_device_new(codec->card, SNDRV_DEV_JACK, beep, &ops); if (err < 0) goto err_input; return 0; err_input: input_free_device(beep->dev); err_free: kfree(beep); codec->beep = NULL; return err; }