diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-12-26 14:52:54 +0000 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-12-26 14:52:54 +0000 |
commit | 7f50548abb5454bd82c25aae15f0a3bf6a530f46 (patch) | |
tree | 175b5d695437151f0f9f778ad8eb7f274468842f /sound/pci/hda/hda_codec.c | |
parent | b3172f222ab5afdc91ea058bd11c42cf169728f3 (diff) | |
parent | 6b7b284958d47b77d06745b36bc7f36dab769d9b (diff) |
Merge commit 'v2.6.33-rc2' into for-2.6.33
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 617 |
1 files changed, 520 insertions, 97 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index af989f660cc..950ee5cfcac 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -30,6 +30,7 @@ #include <sound/tlv.h> #include <sound/initval.h> #include "hda_local.h" +#include "hda_beep.h" #include <sound/hda_hwdep.h> /* @@ -93,6 +94,13 @@ static void hda_keep_power_on(struct hda_codec *codec); static inline void hda_keep_power_on(struct hda_codec *codec) {} #endif +/** + * snd_hda_get_jack_location - Give a location string of the jack + * @cfg: pin default config value + * + * Parse the pin default config value and returns the string of the + * jack location, e.g. "Rear", "Front", etc. + */ const char *snd_hda_get_jack_location(u32 cfg) { static char *bases[7] = { @@ -120,6 +128,13 @@ const char *snd_hda_get_jack_location(u32 cfg) } EXPORT_SYMBOL_HDA(snd_hda_get_jack_location); +/** + * snd_hda_get_jack_connectivity - Give a connectivity string of the jack + * @cfg: pin default config value + * + * Parse the pin default config value and returns the string of the + * jack connectivity, i.e. external or internal connection. + */ const char *snd_hda_get_jack_connectivity(u32 cfg) { static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; @@ -128,6 +143,13 @@ const char *snd_hda_get_jack_connectivity(u32 cfg) } EXPORT_SYMBOL_HDA(snd_hda_get_jack_connectivity); +/** + * snd_hda_get_jack_type - Give a type string of the jack + * @cfg: pin default config value + * + * Parse the pin default config value and returns the string of the + * jack type, i.e. the purpose of the jack, such as Line-Out or CD. + */ const char *snd_hda_get_jack_type(u32 cfg) { static char *jack_types[16] = { @@ -515,6 +537,7 @@ static int snd_hda_bus_dev_register(struct snd_device *device) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { snd_hda_hwdep_add_sysfs(codec); + snd_hda_hwdep_add_power_sysfs(codec); } return 0; } @@ -820,6 +843,16 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, return 0; } +/** + * snd_hda_codec_set_pincfg - Override a pin default configuration + * @codec: the HDA codec + * @nid: NID to set the pin config + * @cfg: the pin default config value + * + * Override a pin default configuration value in the cache. + * This value can be read by snd_hda_codec_get_pincfg() in a higher + * priority than the real hardware value. + */ int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid, unsigned int cfg) { @@ -827,7 +860,15 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg); -/* get the current pin config value of the given pin NID */ +/** + * snd_hda_codec_get_pincfg - Obtain a pin-default configuration + * @codec: the HDA codec + * @nid: NID to get the pin config + * + * Get the current pin config value of the given pin NID. + * If the pincfg value is cached or overridden via sysfs or driver, + * returns the cached value. + */ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) { struct hda_pincfg *pin; @@ -944,7 +985,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr mutex_init(&codec->control_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); - snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); + snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60); snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); if (codec->bus->modelname) { @@ -1026,6 +1067,15 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr } EXPORT_SYMBOL_HDA(snd_hda_codec_new); +/** + * snd_hda_codec_configure - (Re-)configure the HD-audio codec + * @codec: the HDA codec + * + * Start parsing of the given codec tree and (re-)initialize the whole + * patch instance. + * + * Returns 0 if successful or a negative error code. + */ int snd_hda_codec_configure(struct hda_codec *codec) { int err; @@ -1036,11 +1086,6 @@ int snd_hda_codec_configure(struct hda_codec *codec) if (err < 0) return err; } - /* audio codec should override the mixer name */ - if (codec->afg || !*codec->bus->card->mixername) - snprintf(codec->bus->card->mixername, - sizeof(codec->bus->card->mixername), - "%s %s", codec->vendor_name, codec->chip_name); if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); @@ -1059,6 +1104,11 @@ int snd_hda_codec_configure(struct hda_codec *codec) patched: if (!err && codec->patch_ops.unsol_event) err = init_unsol_queue(codec->bus); + /* audio codec should override the mixer name */ + if (!err && (codec->afg || !*codec->bus->card->mixername)) + snprintf(codec->bus->card->mixername, + sizeof(codec->bus->card->mixername), + "%s %s", codec->vendor_name, codec->chip_name); return err; } EXPORT_SYMBOL_HDA(snd_hda_codec_configure); @@ -1088,6 +1138,11 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); +/** + * snd_hda_codec_cleanup_stream - clean up the codec for closing + * @codec: the CODEC to clean up + * @nid: the NID to clean up + */ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) { if (!nid) @@ -1163,8 +1218,17 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key) return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key); } -/* - * query AMP capabilities for the given widget and direction +/** + * query_amp_caps - query AMP capabilities + * @codec: the HD-auio codec + * @nid: the NID to query + * @direction: either #HDA_INPUT or #HDA_OUTPUT + * + * Query AMP capabilities for the given widget and direction. + * Returns the obtained capability bits. + * + * When cap bits have been already read, this doesn't read again but + * returns the cached value. */ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) { @@ -1187,6 +1251,19 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) } EXPORT_SYMBOL_HDA(query_amp_caps); +/** + * snd_hda_override_amp_caps - Override the AMP capabilities + * @codec: the CODEC to clean up + * @nid: the NID to clean up + * @direction: either #HDA_INPUT or #HDA_OUTPUT + * @caps: the capability bits to set + * + * Override the cached AMP caps bits value by the given one. + * This function is useful if the driver needs to adjust the AMP ranges, + * e.g. limit to 0dB, etc. + * + * Returns zero if successful or a negative error code. + */ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps) { @@ -1222,6 +1299,17 @@ static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid) return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); } +/** + * snd_hda_query_pin_caps - Query PIN capabilities + * @codec: the HD-auio codec + * @nid: the NID to query + * + * Query PIN capabilities for the given widget. + * Returns the obtained capability bits. + * + * When cap bits have been already read, this doesn't read again but + * returns the cached value. + */ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) { return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid), @@ -1229,6 +1317,40 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); +/** + * snd_hda_pin_sense - execute pin sense measurement + * @codec: the CODEC to sense + * @nid: the pin NID to sense + * + * Execute necessary pin sense measurement and return its Presence Detect, + * Impedance, ELD Valid etc. status bits. + */ +u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) +{ + u32 pincap = snd_hda_query_pin_caps(codec, nid); + + if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ + snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); + + return snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_SENSE, 0); +} +EXPORT_SYMBOL_HDA(snd_hda_pin_sense); + +/** + * snd_hda_jack_detect - query pin Presence Detect status + * @codec: the CODEC to sense + * @nid: the pin NID to sense + * + * Query and return the pin's Presence Detect status. + */ +int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) +{ + u32 sense = snd_hda_pin_sense(codec, nid); + return !!(sense & AC_PINSENSE_PRESENCE); +} +EXPORT_SYMBOL_HDA(snd_hda_jack_detect); + /* * read the current volume to info * if the cache exists, read the cache value. @@ -1269,8 +1391,15 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, info->vol[ch] = val; } -/* - * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. +/** + * snd_hda_codec_amp_read - Read AMP value + * @codec: HD-audio codec + * @nid: NID to read the AMP value + * @ch: channel (left=0 or right=1) + * @direction: #HDA_INPUT or #HDA_OUTPUT + * @index: the index value (only for input direction) + * + * Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. */ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) @@ -1283,8 +1412,18 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, } EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read); -/* - * update the AMP value, mask = bit mask to set, val = the value +/** + * snd_hda_codec_amp_update - update the AMP value + * @codec: HD-audio codec + * @nid: NID to read the AMP value + * @ch: channel (left=0 or right=1) + * @direction: #HDA_INPUT or #HDA_OUTPUT + * @idx: the index value (only for input direction) + * @mask: bit mask to set + * @val: the bits value to set + * + * Update the AMP value with a bit mask. + * Returns 0 if the value is unchanged, 1 if changed. */ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val) @@ -1303,8 +1442,17 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, } EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update); -/* - * update the AMP stereo with the same mask and value +/** + * snd_hda_codec_amp_stereo - update the AMP stereo values + * @codec: HD-audio codec + * @nid: NID to read the AMP value + * @direction: #HDA_INPUT or #HDA_OUTPUT + * @idx: the index value (only for input direction) + * @mask: bit mask to set + * @val: the bits value to set + * + * Update the AMP values like snd_hda_codec_amp_update(), but for a + * stereo widget with the same mask and value. */ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, int direction, int idx, int mask, int val) @@ -1318,7 +1466,12 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); #ifdef SND_HDA_NEEDS_RESUME -/* resume the all amp commands from the cache */ +/** + * snd_hda_codec_resume_amp - Resume all AMP commands from the cache + * @codec: HD-audio codec + * + * Resume the all amp commands from the cache. + */ void snd_hda_codec_resume_amp(struct hda_codec *codec) { struct hda_amp_info *buffer = codec->amp_cache.buf.list; @@ -1344,7 +1497,12 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); #endif /* SND_HDA_NEEDS_RESUME */ -/* volume */ +/** + * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1400,6 +1558,12 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, HDA_AMP_VOLMASK, val); } +/** + * snd_hda_mixer_amp_volume_get - Get callback for a standard AMP mixer volume + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1419,6 +1583,12 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); +/** + * snd_hda_mixer_amp_volume_put - Put callback for a standard AMP mixer volume + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1443,6 +1613,12 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_put); +/** + * snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) { @@ -1472,8 +1648,16 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_tlv); -/* - * set (static) TLV for virtual master volume; recalculated as max 0dB +/** + * snd_hda_set_vmaster_tlv - Set TLV for a virtual master control + * @codec: HD-audio codec + * @nid: NID of a reference widget + * @dir: #HDA_INPUT or #HDA_OUTPUT + * @tlv: TLV data to be stored, at least 4 elements + * + * Set (static) TLV data for a virtual master volume using the AMP caps + * obtained from the reference NID. + * The volume range is recalculated as if the max volume is 0dB. */ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int *tlv) @@ -1507,6 +1691,13 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec, return snd_ctl_find_id(codec->bus->card, &id); } +/** + * snd_hda_find_mixer_ctl - Find a mixer control element with the given name + * @codec: HD-audio codec + * @name: ctl id name string + * + * Get the control element with the given id string and IFACE_MIXER. + */ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name) { @@ -1514,30 +1705,57 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); -/* Add a control element and assign to the codec */ -int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) +/** + * snd_hda_ctl-add - Add a control element and assign to the codec + * @codec: HD-audio codec + * @nid: corresponding NID (optional) + * @kctl: the control element to assign + * + * Add the given control element to an array inside the codec instance. + * All control elements belonging to a codec are supposed to be added + * by this function so that a proper clean-up works at the free or + * reconfiguration time. + * + * If non-zero @nid is passed, the NID is assigned to the control element. + * The assignment is shown in the codec proc file. + * + * snd_hda_ctl_add() checks the control subdev id field whether + * #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower + * bits value is taken as the NID to assign. + */ +int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, + struct snd_kcontrol *kctl) { int err; - struct snd_kcontrol **knewp; + struct hda_nid_item *item; + if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) { + if (nid == 0) + nid = kctl->id.subdevice & 0xffff; + kctl->id.subdevice = 0; + } err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; - knewp = snd_array_new(&codec->mixers); - if (!knewp) + item = snd_array_new(&codec->mixers); + if (!item) return -ENOMEM; - *knewp = kctl; + item->kctl = kctl; + item->nid = nid; return 0; } EXPORT_SYMBOL_HDA(snd_hda_ctl_add); -/* Clear all controls assigned to the given codec */ +/** + * snd_hda_ctls_clear - Clear all controls assigned to the given codec + * @codec: HD-audio codec + */ void snd_hda_ctls_clear(struct hda_codec *codec) { int i; - struct snd_kcontrol **kctls = codec->mixers.list; + struct hda_nid_item *items = codec->mixers.list; for (i = 0; i < codec->mixers.used; i++) - snd_ctl_remove(codec->bus->card, kctls[i]); + snd_ctl_remove(codec->bus->card, items[i].kctl); snd_array_free(&codec->mixers); } @@ -1563,6 +1781,16 @@ static void hda_unlock_devices(struct snd_card *card) spin_unlock(&card->files_lock); } +/** + * snd_hda_codec_reset - Clear all objects assigned to the codec + * @codec: HD-audio codec + * + * This frees the all PCM and control elements assigned to the codec, and + * clears the caches and restores the pin default configurations. + * + * When a device is being used, it returns -EBSY. If successfully freed, + * returns zero. + */ int snd_hda_codec_reset(struct hda_codec *codec) { struct snd_card *card = codec->bus->card; @@ -1626,7 +1854,22 @@ int snd_hda_codec_reset(struct hda_codec *codec) return 0; } -/* create a virtual master control and add slaves */ +/** + * snd_hda_add_vmaster - create a virtual master control and add slaves + * @codec: HD-audio codec + * @name: vmaster control name + * @tlv: TLV data (optional) + * @slaves: slave control names (optional) + * + * Create a virtual master control with the given name. The TLV data + * must be either NULL or a valid data. + * + * @slaves is a NULL-terminated array of strings, each of which is a + * slave control name. All controls with these names are assigned to + * the new virtual master control. + * + * This function returns zero if successful or a negative error code. + */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves) { @@ -1643,7 +1886,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, kctl = snd_ctl_make_virtual_master(name, tlv); if (!kctl) return -ENOMEM; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; @@ -1668,7 +1911,12 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, } EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); -/* switch */ +/** + * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1682,6 +1930,12 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_info); +/** + * snd_hda_mixer_amp_switch_get - Get callback for a standard AMP mixer switch + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1702,6 +1956,12 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get); +/** + * snd_hda_mixer_amp_switch_put - Put callback for a standard AMP mixer switch + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1733,6 +1993,25 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); +#ifdef CONFIG_SND_HDA_INPUT_BEEP +/** + * snd_hda_mixer_amp_switch_put_beep - Put callback for a beep AMP switch + * + * This function calls snd_hda_enable_beep_device(), which behaves differently + * depending on beep_mode option. + */ +int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + + snd_hda_enable_beep_device(codec, *valp); + return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); +} +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep); +#endif /* CONFIG_SND_HDA_INPUT_BEEP */ + /* * bound volume controls * @@ -1742,6 +2021,12 @@ EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); #define AMP_VAL_IDX_SHIFT 19 #define AMP_VAL_IDX_MASK (0x0f<<19) +/** + * snd_hda_mixer_bind_switch_get - Get callback for a bound volume control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_MUTE*() macros. + */ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1759,6 +2044,12 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); +/** + * snd_hda_mixer_bind_switch_put - Put callback for a bound volume control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_MUTE*() macros. + */ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1783,8 +2074,11 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); -/* - * generic bound volume/swtich controls +/** + * snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. */ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -1803,6 +2097,12 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); +/** + * snd_hda_mixer_bind_ctls_get - Get callback for a generic bound control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. + */ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1820,6 +2120,12 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); +/** + * snd_hda_mixer_bind_ctls_put - Put callback for a generic bound control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. + */ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1843,6 +2149,12 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); +/** + * snd_hda_mixer_bind_tlv - TLV callback for a generic bound control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_VOL() macro. + */ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv) { @@ -2126,7 +2438,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) return -ENOMEM; kctl->id.index = idx; kctl->private_value = nid; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, nid, kctl); if (err < 0) return err; } @@ -2165,14 +2477,19 @@ static struct snd_kcontrol_new spdif_share_sw = { .put = spdif_share_sw_put, }; +/** + * snd_hda_create_spdif_share_sw - create Default PCM switch + * @codec: the HDA codec + * @mout: multi-out instance + */ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, struct hda_multi_out *mout) { if (!mout->dig_out_nid) return 0; /* ATTENTION: here mout is passed as private_data, instead of codec */ - return snd_hda_ctl_add(codec, - snd_ctl_new1(&spdif_share_sw, mout)); + return snd_hda_ctl_add(codec, mout->dig_out_nid, + snd_ctl_new1(&spdif_share_sw, mout)); } EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw); @@ -2276,7 +2593,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) if (!kctl) return -ENOMEM; kctl->private_value = nid; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, nid, kctl); if (err < 0) return err; } @@ -2332,7 +2649,12 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); -/* resume the all commands from the cache */ +/** + * snd_hda_codec_resume_cache - Resume the all commands from the cache + * @codec: HD-audio codec + * + * Execute all verbs recorded in the command caches to resume. + */ void snd_hda_codec_resume_cache(struct hda_codec *codec) { struct hda_cache_head *buffer = codec->cmd_cache.buf.list; @@ -2452,9 +2774,11 @@ static void hda_call_codec_suspend(struct hda_codec *codec) codec->afg ? codec->afg : codec->mfg, AC_PWRST_D3); #ifdef CONFIG_SND_HDA_POWER_SAVE + snd_hda_update_power_acct(codec); cancel_delayed_work(&codec->power_work); codec->power_on = 0; codec->power_transition = 0; + codec->power_jiffies = jiffies; #endif } @@ -2756,8 +3080,12 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, } /** - * snd_hda_is_supported_format - check whether the given node supports - * the format val + * snd_hda_is_supported_format - Check the validity of the format + * @codec: HD-audio codec + * @nid: NID to check + * @format: the HD-audio format value to check + * + * Check whether the given node supports the format value. * * Returns 1 if supported, 0 if not. */ @@ -2877,51 +3205,36 @@ static int set_pcm_default_values(struct hda_codec *codec, return 0; } +/* global */ +const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { + "Audio", "SPDIF", "HDMI", "Modem" +}; + /* * get the empty PCM device number to assign */ static int get_empty_pcm_device(struct hda_bus *bus, int type) { - static const char *dev_name[HDA_PCM_NTYPES] = { - "Audio", "SPDIF", "HDMI", "Modem" - }; - /* starting device index for each PCM type */ - static int dev_idx[HDA_PCM_NTYPES] = { - [HDA_PCM_TYPE_AUDIO] = 0, - [HDA_PCM_TYPE_SPDIF] = 1, - [HDA_PCM_TYPE_HDMI] = 3, - [HDA_PCM_TYPE_MODEM] = 6 + /* audio device indices; not linear to keep compatibility */ + static int audio_idx[HDA_PCM_NTYPES][5] = { + [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 }, + [HDA_PCM_TYPE_SPDIF] = { 1, -1 }, + [HDA_PCM_TYPE_HDMI] = { 3, 7, 8, 9, -1 }, + [HDA_PCM_TYPE_MODEM] = { 6, -1 }, }; - /* normal audio device indices; not linear to keep compatibility */ - static int audio_idx[4] = { 0, 2, 4, 5 }; - int i, dev; - - switch (type) { - case HDA_PCM_TYPE_AUDIO: - for (i = 0; i < ARRAY_SIZE(audio_idx); i++) { - dev = audio_idx[i]; - if (!test_bit(dev, bus->pcm_dev_bits)) - goto ok; - } - snd_printk(KERN_WARNING "Too many audio devices\n"); - return -EAGAIN; - case HDA_PCM_TYPE_SPDIF: - case HDA_PCM_TYPE_HDMI: - case HDA_PCM_TYPE_MODEM: - dev = dev_idx[type]; - if (test_bit(dev, bus->pcm_dev_bits)) { - snd_printk(KERN_WARNING "%s already defined\n", - dev_name[type]); - return -EAGAIN; - } - break; - default: + int i; + + if (type >= HDA_PCM_NTYPES) { snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); return -EINVAL; } - ok: - set_bit(dev, bus->pcm_dev_bits); - return dev; + + for (i = 0; audio_idx[type][i] >= 0 ; i++) + if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits)) + return audio_idx[type][i]; + + snd_printk(KERN_WARNING "Too many %s devices\n", snd_hda_pcm_type_name[type]); + return -EAGAIN; } /* @@ -3159,14 +3472,14 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config); */ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) { - int err; + int err; for (; knew->name; knew++) { struct snd_kcontrol *kctl; kctl = snd_ctl_new1(knew, codec); if (!kctl) return -ENOMEM; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) { if (!codec->addr) return err; @@ -3174,7 +3487,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) if (!kctl) return -ENOMEM; kctl->id.device = codec->addr; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; } @@ -3207,8 +3520,27 @@ static void hda_keep_power_on(struct hda_codec *codec) { codec->power_count++; codec->power_on = 1; + codec->power_jiffies = jiffies; } +/* update the power on/off account with the current jiffies */ +void snd_hda_update_power_acct(struct hda_codec *codec) +{ + unsigned long delta = jiffies - codec->power_jiffies; + if (codec->power_on) + codec->power_on_acct += delta; + else + codec->power_off_acct += delta; + codec->power_jiffies += delta; +} + +/** + * snd_hda_power_up - Power-up the codec + * @codec: HD-audio codec + * + * Increment the power-up counter and power up the hardware really when + * not turned on yet. + */ void snd_hda_power_up(struct hda_codec *codec) { struct hda_bus *bus = codec->bus; @@ -3217,7 +3549,9 @@ void snd_hda_power_up(struct hda_codec *codec) if (codec->power_on || codec->power_transition) return; + snd_hda_update_power_acct(codec); codec->power_on = 1; + codec->power_jiffies = jiffies; if (bus->ops.pm_notify) bus->ops.pm_notify(bus); hda_call_codec_resume(codec); @@ -3229,9 +3563,13 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up); #define power_save(codec) \ ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) -#define power_save(codec) \ - ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) - +/** + * snd_hda_power_down - Power-down the codec + * @codec: HD-audio codec + * + * Decrement the power-up counter and schedules the power-off work if + * the counter rearches to zero. + */ void snd_hda_power_down(struct hda_codec *codec) { --codec->power_count; @@ -3245,6 +3583,19 @@ void snd_hda_power_down(struct hda_codec *codec) } EXPORT_SYMBOL_HDA(snd_hda_power_down); +/** + * snd_hda_check_amp_list_power - Check the amp list and update the power + * @codec: HD-audio codec + * @check: the object containing an AMP list and the status + * @nid: NID to check / update + * + * Check whether the given NID is in the amp list. If it's in the list, + * check the current AMP status, and update the the power-status according + * to the mute status. + * + * This function is supposed to be set or called from the check_power_status + * patch ops. + */ int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, hda_nid_t nid) @@ -3286,6 +3637,10 @@ EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power); /* * Channel mode helper */ + +/** + * snd_hda_ch_mode_info - Info callback helper for the channel mode enum + */ int snd_hda_ch_mode_info(struct hda_codec *codec, struct snd_ctl_elem_info *uinfo, const struct hda_channel_mode *chmode, @@ -3302,6 +3657,9 @@ int snd_hda_ch_mode_info(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_ch_mode_info); +/** + * snd_hda_ch_mode_get - Get callback helper for the channel mode enum + */ int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, const struct hda_channel_mode *chmode, @@ -3320,6 +3678,9 @@ int snd_hda_ch_mode_get(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_ch_mode_get); +/** + * snd_hda_ch_mode_put - Put callback helper for the channel mode enum + */ int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, const struct hda_channel_mode *chmode, @@ -3344,6 +3705,10 @@ EXPORT_SYMBOL_HDA(snd_hda_ch_mode_put); /* * input MUX helper */ + +/** + * snd_hda_input_mux_info_info - Info callback helper for the input-mux enum + */ int snd_hda_input_mux_info(const struct hda_input_mux *imux, struct snd_ctl_elem_info *uinfo) { @@ -3362,6 +3727,9 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, } EXPORT_SYMBOL_HDA(snd_hda_input_mux_info); +/** + * snd_hda_input_mux_info_put - Put callback helper for the input-mux enum + */ int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, struct snd_ctl_elem_value *ucontrol, @@ -3421,8 +3789,29 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) } } -/* - * open the digital out in the exclusive mode +/** + * snd_hda_bus_reboot_notify - call the reboot notifier of each codec + * @bus: HD-audio bus + */ +void snd_hda_bus_reboot_notify(struct hda_bus *bus) +{ + struct hda_codec *codec; + + if (!bus) + return; + list_for_each_entry(codec, &bus->codec_list, list) { +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!codec->power_on) + continue; +#endif + if (codec->patch_ops.reboot_notify) + codec->patch_ops.reboot_notify(codec); + } +} +EXPORT_SYMBOL_HDA(snd_hda_bus_reboot_notify); + +/** + * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode */ int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout) @@ -3437,6 +3826,9 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_open); +/** + * snd_hda_multi_out_dig_prepare - prepare the digital out stream + */ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, unsigned int stream_tag, @@ -3450,6 +3842,9 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare); +/** + * snd_hda_multi_out_dig_cleanup - clean-up the digital out stream + */ int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) { @@ -3460,8 +3855,8 @@ int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_cleanup); -/* - * release the digital out +/** + * snd_hda_multi_out_dig_close - release the digital out stream */ int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout) @@ -3473,8 +3868,12 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_close); -/* - * set up more restrictions for analog out +/** + * snd_hda_multi_out_analog_open - open analog outputs + * + * Open analog outputs and set up the hw-constraints. + * If the digital outputs can be opened as slave, open the digital + * outputs, too. */ int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, @@ -3519,9 +3918,11 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_open); -/* - * set up the i/o for analog out - * when the digital out is available, copy the front out to digital out, too. +/** + * snd_hda_multi_out_analog_prepare - Preapre the analog outputs. + * + * Set up the i/o for analog out. + * When the digital out is available, copy the front out to digital out, too. */ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, @@ -3578,8 +3979,8 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare); -/* - * clean up the setting for analog out +/** + * snd_hda_multi_out_analog_cleanup - clean up the setting for analog out */ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) @@ -3965,8 +4366,14 @@ EXPORT_SYMBOL_HDA(snd_hda_resume); * generic arrays */ -/* get a new element from the given array - * if it exceeds the pre-allocated array size, re-allocate the array +/** + * snd_array_new - get a new element from the given array + * @array: the array object + * + * Get a new element from the given array. If it exceeds the + * pre-allocated array size, re-allocate the array. + * + * Returns NULL if allocation failed. */ void *snd_array_new(struct snd_array *array) { @@ -3990,7 +4397,10 @@ void *snd_array_new(struct snd_array *array) } EXPORT_SYMBOL_HDA(snd_array_new); -/* free the given array elements */ +/** + * snd_array_free - free the given array elements + * @array: the array object + */ void snd_array_free(struct snd_array *array) { kfree(array->list); @@ -4000,7 +4410,12 @@ 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) @@ -4019,6 +4434,14 @@ void snd_print_pcm_rates(int pcm, char *buf, int buflen) } 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 + * @buflen: the max buffer length + * + * used by hda_proc.c and hda_eld.c + */ void snd_print_pcm_bits(int pcm, char *buf, int buflen) { static unsigned int bits[] = { 8, 16, 20, 24, 32 }; |