Loading include/linux/input.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -644,6 +644,7 @@ struct input_absinfo { #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_DOCK 0x05 /* set = plugged into dock */ #define SW_DOCK 0x05 /* set = plugged into dock */ #define SW_LINEOUT_INSERT 0x06 /* set = inserted */ #define SW_MAX 0x0f #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) #define SW_CNT (SW_MAX+1) Loading include/sound/jack.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -35,6 +35,7 @@ enum snd_jack_types { SND_JACK_HEADPHONE = 0x0001, SND_JACK_HEADPHONE = 0x0001, SND_JACK_MICROPHONE = 0x0002, SND_JACK_MICROPHONE = 0x0002, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, SND_JACK_LINEOUT = 0x0004, }; }; struct snd_jack { struct snd_jack { Loading sound/core/jack.c +8 −1 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,7 @@ static int snd_jack_dev_free(struct snd_device *device) else else input_free_device(jack->input_dev); input_free_device(jack->input_dev); kfree(jack->id); kfree(jack); kfree(jack); return 0; return 0; Loading Loading @@ -87,7 +88,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (jack == NULL) if (jack == NULL) return -ENOMEM; return -ENOMEM; jack->id = id; jack->id = kstrdup(id, GFP_KERNEL); jack->input_dev = input_allocate_device(); jack->input_dev = input_allocate_device(); if (jack->input_dev == NULL) { if (jack->input_dev == NULL) { Loading @@ -102,6 +103,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (type & SND_JACK_HEADPHONE) if (type & SND_JACK_HEADPHONE) input_set_capability(jack->input_dev, EV_SW, input_set_capability(jack->input_dev, EV_SW, SW_HEADPHONE_INSERT); SW_HEADPHONE_INSERT); if (type & SND_JACK_LINEOUT) input_set_capability(jack->input_dev, EV_SW, SW_LINEOUT_INSERT); if (type & SND_JACK_MICROPHONE) if (type & SND_JACK_MICROPHONE) input_set_capability(jack->input_dev, EV_SW, input_set_capability(jack->input_dev, EV_SW, SW_MICROPHONE_INSERT); SW_MICROPHONE_INSERT); Loading Loading @@ -150,6 +154,9 @@ void snd_jack_report(struct snd_jack *jack, int status) if (jack->type & SND_JACK_HEADPHONE) if (jack->type & SND_JACK_HEADPHONE) input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, status & SND_JACK_HEADPHONE); status & SND_JACK_HEADPHONE); if (jack->type & SND_JACK_LINEOUT) input_report_switch(jack->input_dev, SW_LINEOUT_INSERT, status & SND_JACK_LINEOUT); if (jack->type & SND_JACK_MICROPHONE) if (jack->type & SND_JACK_MICROPHONE) input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, status & SND_JACK_MICROPHONE); status & SND_JACK_MICROPHONE); Loading sound/pci/Kconfig +1 −0 Original line number Original line Diff line number Diff line Loading @@ -501,6 +501,7 @@ config SND_HDA_INTEL tristate "Intel HD Audio" tristate "Intel HD Audio" select SND_PCM select SND_PCM select SND_VMASTER select SND_VMASTER select SND_JACK if INPUT=y || INPUT=SND help help Say Y here to include support for Intel "High Definition Say Y here to include support for Intel "High Definition Audio" (Azalia) motherboard devices. Audio" (Azalia) motherboard devices. Loading sound/pci/hda/hda_codec.c +333 −95 Original line number Original line Diff line number Diff line Loading @@ -107,6 +107,52 @@ static void hda_keep_power_on(struct hda_codec *codec); static inline void hda_keep_power_on(struct hda_codec *codec) {} static inline void hda_keep_power_on(struct hda_codec *codec) {} #endif #endif const char *snd_hda_get_jack_location(u32 cfg) { static char *bases[7] = { "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", }; static unsigned char specials_idx[] = { 0x07, 0x08, 0x17, 0x18, 0x19, 0x37, 0x38 }; static char *specials[] = { "Rear Panel", "Drive Bar", "Riser", "HDMI", "ATAPI", "Mobile-In", "Mobile-Out" }; int i; cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; if ((cfg & 0x0f) < 7) return bases[cfg & 0x0f]; for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { if (cfg == specials_idx[i]) return specials[i]; } return "UNKNOWN"; } const char *snd_hda_get_jack_connectivity(u32 cfg) { static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; } const char *snd_hda_get_jack_type(u32 cfg) { static char *jack_types[16] = { "Line Out", "Speaker", "HP Out", "CD", "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", "Line In", "Aux", "Mic", "Telephony", "SPDIF In", "Digitial In", "Reserved", "Other" }; return jack_types[(cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT]; } /** /** * snd_hda_codec_read - send a command and get the response * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec * @codec: the HDA codec Loading Loading @@ -344,7 +390,7 @@ static void process_unsol_events(struct work_struct *work) /* /* * initialize unsolicited queue * initialize unsolicited queue */ */ static int __devinit init_unsol_queue(struct hda_bus *bus) static int init_unsol_queue(struct hda_bus *bus) { { struct hda_bus_unsolicited *unsol; struct hda_bus_unsolicited *unsol; Loading Loading @@ -393,6 +439,20 @@ static int snd_hda_bus_dev_free(struct snd_device *device) return snd_hda_bus_free(bus); return snd_hda_bus_free(bus); } } #ifdef CONFIG_SND_HDA_HWDEP static int snd_hda_bus_dev_register(struct snd_device *device) { struct hda_bus *bus = device->device_data; struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { snd_hda_hwdep_add_sysfs(codec); } return 0; } #else #define snd_hda_bus_dev_register NULL #endif /** /** * snd_hda_bus_new - create a HDA bus * snd_hda_bus_new - create a HDA bus * @card: the card entry * @card: the card entry Loading @@ -408,6 +468,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, struct hda_bus *bus; struct hda_bus *bus; int err; int err; static struct snd_device_ops dev_ops = { static struct snd_device_ops dev_ops = { .dev_register = snd_hda_bus_dev_register, .dev_free = snd_hda_bus_dev_free, .dev_free = snd_hda_bus_dev_free, }; }; Loading Loading @@ -446,7 +507,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, #ifdef CONFIG_SND_HDA_GENERIC #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ #define is_generic_config(codec) \ (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) (codec->modelname && !strcmp(codec->modelname, "generic")) #else #else #define is_generic_config(codec) 0 #define is_generic_config(codec) 0 #endif #endif Loading @@ -454,7 +515,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, /* /* * find a matching codec preset * find a matching codec preset */ */ static const struct hda_codec_preset __devinit * static const struct hda_codec_preset * find_codec_preset(struct hda_codec *codec) find_codec_preset(struct hda_codec *codec) { { const struct hda_codec_preset **tbl, *preset; const struct hda_codec_preset **tbl, *preset; Loading @@ -481,15 +542,14 @@ find_codec_preset(struct hda_codec *codec) } } /* /* * snd_hda_get_codec_name - store the codec name * get_codec_name - store the codec name */ */ void snd_hda_get_codec_name(struct hda_codec *codec, static int get_codec_name(struct hda_codec *codec) char *name, int namelen) { { const struct hda_vendor_id *c; const struct hda_vendor_id *c; const char *vendor = NULL; const char *vendor = NULL; u16 vendor_id = codec->vendor_id >> 16; u16 vendor_id = codec->vendor_id >> 16; char tmp[16]; char tmp[16], name[32]; for (c = hda_vendor_ids; c->id; c++) { for (c = hda_vendor_ids; c->id; c++) { if (c->id == vendor_id) { if (c->id == vendor_id) { Loading @@ -502,10 +562,15 @@ void snd_hda_get_codec_name(struct hda_codec *codec, vendor = tmp; vendor = tmp; } } if (codec->preset && codec->preset->name) if (codec->preset && codec->preset->name) snprintf(name, namelen, "%s %s", vendor, codec->preset->name); snprintf(name, sizeof(name), "%s %s", vendor, codec->preset->name); else else snprintf(name, namelen, "%s ID %x", vendor, snprintf(name, sizeof(name), "%s ID %x", vendor, codec->vendor_id & 0xffff); codec->vendor_id & 0xffff); codec->name = kstrdup(name, GFP_KERNEL); if (!codec->name) return -ENOMEM; return 0; } } /* /* Loading Loading @@ -570,11 +635,14 @@ static void snd_hda_codec_free(struct hda_codec *codec) flush_scheduled_work(); flush_scheduled_work(); #endif #endif list_del(&codec->list); list_del(&codec->list); snd_array_free(&codec->mixers); codec->bus->caddr_tbl[codec->addr] = NULL; codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) if (codec->patch_ops.free) codec->patch_ops.free(codec); codec->patch_ops.free(codec); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); free_hda_cache(&codec->cmd_cache); kfree(codec->name); kfree(codec->modelname); kfree(codec->wcaps); kfree(codec->wcaps); kfree(codec); kfree(codec); } } Loading Loading @@ -616,6 +684,14 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, mutex_init(&codec->spdif_mutex); mutex_init(&codec->spdif_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { snd_hda_codec_free(codec); return -ENODEV; } } #ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE INIT_DELAYED_WORK(&codec->power_work, hda_power_work); INIT_DELAYED_WORK(&codec->power_work, hda_power_work); Loading Loading @@ -661,12 +737,41 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, snd_hda_codec_read(codec, nid, 0, snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_SUBSYSTEM_ID, 0); AC_VERB_GET_SUBSYSTEM_ID, 0); } } if (bus->modelname) codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); err = snd_hda_codec_configure(codec); if (err < 0) { snd_hda_codec_free(codec); return err; } snd_hda_codec_proc_new(codec); snd_hda_create_hwdep(codec); sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component); if (codecp) *codecp = codec; return 0; } int snd_hda_codec_configure(struct hda_codec *codec) { int err; codec->preset = find_codec_preset(codec); codec->preset = find_codec_preset(codec); if (!codec->name) { err = get_codec_name(codec); if (err < 0) return err; } /* audio codec should override the mixer name */ /* audio codec should override the mixer name */ if (codec->afg || !*bus->card->mixername) if (codec->afg || !*codec->bus->card->mixername) snd_hda_get_codec_name(codec, bus->card->mixername, strlcpy(codec->bus->card->mixername, codec->name, sizeof(bus->card->mixername)); sizeof(codec->bus->card->mixername)); if (is_generic_config(codec)) { if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); err = snd_hda_parse_generic_codec(codec); Loading @@ -683,27 +788,11 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, printk(KERN_ERR "hda-codec: No codec parser is available\n"); printk(KERN_ERR "hda-codec: No codec parser is available\n"); patched: patched: if (err < 0) { if (!err && codec->patch_ops.unsol_event) snd_hda_codec_free(codec); err = init_unsol_queue(codec->bus); return err; return err; } } if (codec->patch_ops.unsol_event) init_unsol_queue(bus); snd_hda_codec_proc_new(codec); #ifdef CONFIG_SND_HDA_HWDEP snd_hda_create_hwdep(codec); #endif sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component); if (codecp) *codecp = codec; return 0; } /** /** * snd_hda_codec_setup_stream - set up the codec for streaming * snd_hda_codec_setup_stream - set up the codec for streaming * @codec: the CODEC to set up * @codec: the CODEC to set up Loading Loading @@ -756,12 +845,12 @@ static void __devinit init_hda_cache(struct hda_cache_rec *cache, { { memset(cache, 0, sizeof(*cache)); memset(cache, 0, sizeof(*cache)); memset(cache->hash, 0xff, sizeof(cache->hash)); memset(cache->hash, 0xff, sizeof(cache->hash)); cache->record_size = record_size; snd_array_init(&cache->buf, record_size, 64); } } static void free_hda_cache(struct hda_cache_rec *cache) static void free_hda_cache(struct hda_cache_rec *cache) { { kfree(cache->buffer); snd_array_free(&cache->buf); } } /* query the hash. allocate an entry if not found. */ /* query the hash. allocate an entry if not found. */ Loading @@ -770,38 +859,18 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, { { u16 idx = key % (u16)ARRAY_SIZE(cache->hash); u16 idx = key % (u16)ARRAY_SIZE(cache->hash); u16 cur = cache->hash[idx]; u16 cur = cache->hash[idx]; struct hda_cache_head *info_head = cache->buf.list; struct hda_cache_head *info; struct hda_cache_head *info; while (cur != 0xffff) { while (cur != 0xffff) { info = (struct hda_cache_head *)(cache->buffer + info = &info_head[cur]; cur * cache->record_size); if (info->key == key) if (info->key == key) return info; return info; cur = info->next; cur = info->next; } } /* add a new hash entry */ /* add a new hash entry */ if (cache->num_entries >= cache->size) { info = snd_array_new(&cache->buf); /* reallocate the array */ unsigned int new_size = cache->size + 64; void *new_buffer; new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); if (!new_buffer) { snd_printk(KERN_ERR "hda_codec: " "can't malloc amp_info\n"); return NULL; } if (cache->buffer) { memcpy(new_buffer, cache->buffer, cache->size * cache->record_size); kfree(cache->buffer); } cache->size = new_size; cache->buffer = new_buffer; } cur = cache->num_entries++; info = (struct hda_cache_head *)(cache->buffer + cur * cache->record_size); info->key = key; info->key = key; info->val = 0; info->val = 0; info->next = cache->hash[idx]; info->next = cache->hash[idx]; Loading Loading @@ -942,10 +1011,10 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, /* resume the all amp commands from the cache */ /* resume the all amp commands from the cache */ void snd_hda_codec_resume_amp(struct hda_codec *codec) void snd_hda_codec_resume_amp(struct hda_codec *codec) { { struct hda_amp_info *buffer = codec->amp_cache.buffer; struct hda_amp_info *buffer = codec->amp_cache.buf.list; int i; int i; for (i = 0; i < codec->amp_cache.size; i++, buffer++) { for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) { u32 key = buffer->head.key; u32 key = buffer->head.key; hda_nid_t nid; hda_nid_t nid; unsigned int idx, dir, ch; unsigned int idx, dir, ch; Loading Loading @@ -1097,6 +1166,57 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, return _snd_hda_find_mixer_ctl(codec, name, 0); return _snd_hda_find_mixer_ctl(codec, name, 0); } } /* Add a control element and assign to the codec */ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) { int err; struct snd_kcontrol **knewp; err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; knewp = snd_array_new(&codec->mixers); if (!knewp) return -ENOMEM; *knewp = kctl; return 0; } /* Clear all controls assigned to the given codec */ void snd_hda_ctls_clear(struct hda_codec *codec) { int i; struct snd_kcontrol **kctls = codec->mixers.list; for (i = 0; i < codec->mixers.used; i++) snd_ctl_remove(codec->bus->card, kctls[i]); snd_array_free(&codec->mixers); } void snd_hda_codec_reset(struct hda_codec *codec) { int i; #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); flush_scheduled_work(); #endif snd_hda_ctls_clear(codec); /* relase PCMs */ for (i = 0; i < codec->num_pcms; i++) { if (codec->pcm_info[i].pcm) snd_device_free(codec->bus->card, codec->pcm_info[i].pcm); } if (codec->patch_ops.free) codec->patch_ops.free(codec); codec->spec = NULL; free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; } /* create a virtual master control and add slaves */ /* create a virtual master control and add slaves */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves) unsigned int *tlv, const char **slaves) Loading @@ -1114,7 +1234,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, kctl = snd_ctl_make_virtual_master(name, tlv); kctl = snd_ctl_make_virtual_master(name, tlv); if (!kctl) if (!kctl) return -ENOMEM; return -ENOMEM; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) if (err < 0) return err; return err; Loading Loading @@ -1578,7 +1698,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) kctl = snd_ctl_new1(dig_mix, codec); kctl = snd_ctl_new1(dig_mix, codec); kctl->id.index = idx; kctl->id.index = idx; kctl->private_value = nid; kctl->private_value = nid; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) if (err < 0) return err; return err; } } Loading Loading @@ -1622,7 +1742,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, if (!mout->dig_out_nid) if (!mout->dig_out_nid) return 0; return 0; /* ATTENTION: here mout is passed as private_data, instead of codec */ /* ATTENTION: here mout is passed as private_data, instead of codec */ return snd_ctl_add(codec->bus->card, return snd_hda_ctl_add(codec, snd_ctl_new1(&spdif_share_sw, mout)); snd_ctl_new1(&spdif_share_sw, mout)); } } Loading Loading @@ -1724,7 +1844,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); kctl = snd_ctl_new1(dig_mix, codec); kctl->private_value = nid; kctl->private_value = nid; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) if (err < 0) return err; return err; } } Loading Loading @@ -1779,10 +1899,10 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, /* resume the all commands from the cache */ /* resume the all commands from the cache */ void snd_hda_codec_resume_cache(struct hda_codec *codec) void snd_hda_codec_resume_cache(struct hda_codec *codec) { { struct hda_cache_head *buffer = codec->cmd_cache.buffer; struct hda_cache_head *buffer = codec->cmd_cache.buf.list; int i; int i; for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) { u32 key = buffer->key; u32 key = buffer->key; if (!key) if (!key) continue; continue; Loading Loading @@ -1867,6 +1987,17 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, } } } } #ifdef CONFIG_SND_HDA_HWDEP /* execute additional init verbs */ static void hda_exec_init_verbs(struct hda_codec *codec) { if (codec->init_verbs.list) snd_hda_sequence_write(codec, codec->init_verbs.list); } #else static inline void hda_exec_init_verbs(struct hda_codec *codec) {} #endif #ifdef SND_HDA_NEEDS_RESUME #ifdef SND_HDA_NEEDS_RESUME /* /* * call suspend and power-down; used both from PM and power-save * call suspend and power-down; used both from PM and power-save Loading @@ -1893,6 +2024,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_set_power_state(codec, hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); AC_PWRST_D0); hda_exec_init_verbs(codec); if (codec->patch_ops.resume) if (codec->patch_ops.resume) codec->patch_ops.resume(codec); codec->patch_ops.resume(codec); else { else { Loading @@ -1918,6 +2050,15 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) struct hda_codec *codec; struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { list_for_each_entry(codec, &bus->codec_list, list) { int err = snd_hda_codec_build_controls(codec); if (err < 0) return err; } return 0; } int snd_hda_codec_build_controls(struct hda_codec *codec) { int err = 0; int err = 0; /* fake as if already powered-on */ /* fake as if already powered-on */ hda_keep_power_on(codec); hda_keep_power_on(codec); Loading @@ -1925,6 +2066,7 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) hda_set_power_state(codec, hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); AC_PWRST_D0); hda_exec_init_verbs(codec); /* continue to initialize... */ /* continue to initialize... */ if (codec->patch_ops.init) if (codec->patch_ops.init) err = codec->patch_ops.init(codec); err = codec->patch_ops.init(codec); Loading @@ -1933,8 +2075,6 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) snd_hda_power_down(codec); snd_hda_power_down(codec); if (err < 0) if (err < 0) return err; return err; } return 0; return 0; } } Loading Loading @@ -2235,7 +2375,7 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, return 0; return 0; } } static int __devinit set_pcm_default_values(struct hda_codec *codec, static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream *info) struct hda_pcm_stream *info) { { /* query support PCM information from the given NID */ /* query support PCM information from the given NID */ Loading @@ -2262,6 +2402,28 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, return 0; return 0; } } /* * attach a new PCM stream */ static int __devinit snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) { struct hda_pcm_stream *info; int stream, err; if (!pcm->name) return -EINVAL; for (stream = 0; stream < 2; stream++) { info = &pcm->stream[stream]; if (info->substreams) { err = set_pcm_default_values(codec, info); if (err < 0) return err; } } return codec->bus->ops.attach_pcm(codec, pcm); } /** /** * snd_hda_build_pcms - build PCM information * snd_hda_build_pcms - build PCM information * @bus: the BUS * @bus: the BUS Loading @@ -2288,25 +2450,67 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, * * * This function returns 0 if successfull, or a negative error code. * This function returns 0 if successfull, or a negative error code. */ */ int __devinit snd_hda_build_pcms(struct hda_bus *bus) int snd_hda_build_pcms(struct hda_bus *bus) { { 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 }; /* normal audio device indices; not linear to keep compatibility */ static int audio_idx[4] = { 0, 2, 4, 5 }; struct hda_codec *codec; struct hda_codec *codec; int num_devs[HDA_PCM_NTYPES]; memset(num_devs, 0, sizeof(num_devs)); list_for_each_entry(codec, &bus->codec_list, list) { list_for_each_entry(codec, &bus->codec_list, list) { unsigned int pcm, s; unsigned int pcm; int err; int err; if (!codec->num_pcms) { if (!codec->patch_ops.build_pcms) if (!codec->patch_ops.build_pcms) continue; continue; err = codec->patch_ops.build_pcms(codec); err = codec->patch_ops.build_pcms(codec); if (err < 0) if (err < 0) return err; return err; } for (pcm = 0; pcm < codec->num_pcms; pcm++) { for (pcm = 0; pcm < codec->num_pcms; pcm++) { for (s = 0; s < 2; s++) { struct hda_pcm *cpcm = &codec->pcm_info[pcm]; struct hda_pcm_stream *info; int type = cpcm->pcm_type; info = &codec->pcm_info[pcm].stream[s]; int dev; if (!info->substreams) switch (type) { case HDA_PCM_TYPE_AUDIO: if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { snd_printk(KERN_WARNING "Too many audio devices\n"); continue; continue; err = set_pcm_default_values(codec, info); } dev = audio_idx[num_devs[type]]; break; case HDA_PCM_TYPE_SPDIF: case HDA_PCM_TYPE_HDMI: case HDA_PCM_TYPE_MODEM: if (num_devs[type]) { snd_printk(KERN_WARNING "%s already defined\n", dev_name[type]); continue; } dev = dev_idx[type]; break; default: snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); continue; } num_devs[type]++; if (!cpcm->pcm) { cpcm->device = dev; err = snd_hda_attach_pcm(codec, cpcm); if (err < 0) if (err < 0) return err; return err; } } Loading @@ -2332,11 +2536,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, const char **models, int num_configs, const char **models, const struct snd_pci_quirk *tbl) const struct snd_pci_quirk *tbl) { { if (codec->bus->modelname && models) { if (codec->modelname && models) { int i; int i; for (i = 0; i < num_configs; i++) { for (i = 0; i < num_configs; i++) { if (models[i] && if (models[i] && !strcmp(codec->bus->modelname, models[i])) { !strcmp(codec->modelname, models[i])) { snd_printd(KERN_INFO "hda_codec: model '%s' is " snd_printd(KERN_INFO "hda_codec: model '%s' is " "selected\n", models[i]); "selected\n", models[i]); return i; return i; Loading Loading @@ -2389,7 +2593,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) kctl = snd_ctl_new1(knew, codec); kctl = snd_ctl_new1(knew, codec); if (!kctl) if (!kctl) return -ENOMEM; return -ENOMEM; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) { if (err < 0) { if (!codec->addr) if (!codec->addr) return err; return err; Loading @@ -2397,7 +2601,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) if (!kctl) if (!kctl) return -ENOMEM; return -ENOMEM; kctl->id.device = codec->addr; kctl->id.device = codec->addr; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) if (err < 0) return err; return err; } } Loading Loading @@ -3138,3 +3342,37 @@ int snd_hda_codecs_inuse(struct hda_bus *bus) } } #endif #endif #endif #endif /* * generic arrays */ /* get a new element from the given array * if it exceeds the pre-allocated array size, re-allocate the array */ void *snd_array_new(struct snd_array *array) { if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; void *nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); if (!nlist) return NULL; if (array->list) { memcpy(nlist, array->list, array->elem_size * array->alloced); kfree(array->list); } array->list = nlist; array->alloced = num; } return array->list + (array->used++ * array->elem_size); } /* free the given array elements */ void snd_array_free(struct snd_array *array) { kfree(array->list); array->used = 0; array->alloced = 0; array->list = NULL; } Loading
include/linux/input.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -644,6 +644,7 @@ struct input_absinfo { #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_DOCK 0x05 /* set = plugged into dock */ #define SW_DOCK 0x05 /* set = plugged into dock */ #define SW_LINEOUT_INSERT 0x06 /* set = inserted */ #define SW_MAX 0x0f #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) #define SW_CNT (SW_MAX+1) Loading
include/sound/jack.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -35,6 +35,7 @@ enum snd_jack_types { SND_JACK_HEADPHONE = 0x0001, SND_JACK_HEADPHONE = 0x0001, SND_JACK_MICROPHONE = 0x0002, SND_JACK_MICROPHONE = 0x0002, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, SND_JACK_LINEOUT = 0x0004, }; }; struct snd_jack { struct snd_jack { Loading
sound/core/jack.c +8 −1 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,7 @@ static int snd_jack_dev_free(struct snd_device *device) else else input_free_device(jack->input_dev); input_free_device(jack->input_dev); kfree(jack->id); kfree(jack); kfree(jack); return 0; return 0; Loading Loading @@ -87,7 +88,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (jack == NULL) if (jack == NULL) return -ENOMEM; return -ENOMEM; jack->id = id; jack->id = kstrdup(id, GFP_KERNEL); jack->input_dev = input_allocate_device(); jack->input_dev = input_allocate_device(); if (jack->input_dev == NULL) { if (jack->input_dev == NULL) { Loading @@ -102,6 +103,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (type & SND_JACK_HEADPHONE) if (type & SND_JACK_HEADPHONE) input_set_capability(jack->input_dev, EV_SW, input_set_capability(jack->input_dev, EV_SW, SW_HEADPHONE_INSERT); SW_HEADPHONE_INSERT); if (type & SND_JACK_LINEOUT) input_set_capability(jack->input_dev, EV_SW, SW_LINEOUT_INSERT); if (type & SND_JACK_MICROPHONE) if (type & SND_JACK_MICROPHONE) input_set_capability(jack->input_dev, EV_SW, input_set_capability(jack->input_dev, EV_SW, SW_MICROPHONE_INSERT); SW_MICROPHONE_INSERT); Loading Loading @@ -150,6 +154,9 @@ void snd_jack_report(struct snd_jack *jack, int status) if (jack->type & SND_JACK_HEADPHONE) if (jack->type & SND_JACK_HEADPHONE) input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, status & SND_JACK_HEADPHONE); status & SND_JACK_HEADPHONE); if (jack->type & SND_JACK_LINEOUT) input_report_switch(jack->input_dev, SW_LINEOUT_INSERT, status & SND_JACK_LINEOUT); if (jack->type & SND_JACK_MICROPHONE) if (jack->type & SND_JACK_MICROPHONE) input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, status & SND_JACK_MICROPHONE); status & SND_JACK_MICROPHONE); Loading
sound/pci/Kconfig +1 −0 Original line number Original line Diff line number Diff line Loading @@ -501,6 +501,7 @@ config SND_HDA_INTEL tristate "Intel HD Audio" tristate "Intel HD Audio" select SND_PCM select SND_PCM select SND_VMASTER select SND_VMASTER select SND_JACK if INPUT=y || INPUT=SND help help Say Y here to include support for Intel "High Definition Say Y here to include support for Intel "High Definition Audio" (Azalia) motherboard devices. Audio" (Azalia) motherboard devices. Loading
sound/pci/hda/hda_codec.c +333 −95 Original line number Original line Diff line number Diff line Loading @@ -107,6 +107,52 @@ static void hda_keep_power_on(struct hda_codec *codec); static inline void hda_keep_power_on(struct hda_codec *codec) {} static inline void hda_keep_power_on(struct hda_codec *codec) {} #endif #endif const char *snd_hda_get_jack_location(u32 cfg) { static char *bases[7] = { "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", }; static unsigned char specials_idx[] = { 0x07, 0x08, 0x17, 0x18, 0x19, 0x37, 0x38 }; static char *specials[] = { "Rear Panel", "Drive Bar", "Riser", "HDMI", "ATAPI", "Mobile-In", "Mobile-Out" }; int i; cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; if ((cfg & 0x0f) < 7) return bases[cfg & 0x0f]; for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { if (cfg == specials_idx[i]) return specials[i]; } return "UNKNOWN"; } const char *snd_hda_get_jack_connectivity(u32 cfg) { static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; } const char *snd_hda_get_jack_type(u32 cfg) { static char *jack_types[16] = { "Line Out", "Speaker", "HP Out", "CD", "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", "Line In", "Aux", "Mic", "Telephony", "SPDIF In", "Digitial In", "Reserved", "Other" }; return jack_types[(cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT]; } /** /** * snd_hda_codec_read - send a command and get the response * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec * @codec: the HDA codec Loading Loading @@ -344,7 +390,7 @@ static void process_unsol_events(struct work_struct *work) /* /* * initialize unsolicited queue * initialize unsolicited queue */ */ static int __devinit init_unsol_queue(struct hda_bus *bus) static int init_unsol_queue(struct hda_bus *bus) { { struct hda_bus_unsolicited *unsol; struct hda_bus_unsolicited *unsol; Loading Loading @@ -393,6 +439,20 @@ static int snd_hda_bus_dev_free(struct snd_device *device) return snd_hda_bus_free(bus); return snd_hda_bus_free(bus); } } #ifdef CONFIG_SND_HDA_HWDEP static int snd_hda_bus_dev_register(struct snd_device *device) { struct hda_bus *bus = device->device_data; struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { snd_hda_hwdep_add_sysfs(codec); } return 0; } #else #define snd_hda_bus_dev_register NULL #endif /** /** * snd_hda_bus_new - create a HDA bus * snd_hda_bus_new - create a HDA bus * @card: the card entry * @card: the card entry Loading @@ -408,6 +468,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, struct hda_bus *bus; struct hda_bus *bus; int err; int err; static struct snd_device_ops dev_ops = { static struct snd_device_ops dev_ops = { .dev_register = snd_hda_bus_dev_register, .dev_free = snd_hda_bus_dev_free, .dev_free = snd_hda_bus_dev_free, }; }; Loading Loading @@ -446,7 +507,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, #ifdef CONFIG_SND_HDA_GENERIC #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ #define is_generic_config(codec) \ (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) (codec->modelname && !strcmp(codec->modelname, "generic")) #else #else #define is_generic_config(codec) 0 #define is_generic_config(codec) 0 #endif #endif Loading @@ -454,7 +515,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, /* /* * find a matching codec preset * find a matching codec preset */ */ static const struct hda_codec_preset __devinit * static const struct hda_codec_preset * find_codec_preset(struct hda_codec *codec) find_codec_preset(struct hda_codec *codec) { { const struct hda_codec_preset **tbl, *preset; const struct hda_codec_preset **tbl, *preset; Loading @@ -481,15 +542,14 @@ find_codec_preset(struct hda_codec *codec) } } /* /* * snd_hda_get_codec_name - store the codec name * get_codec_name - store the codec name */ */ void snd_hda_get_codec_name(struct hda_codec *codec, static int get_codec_name(struct hda_codec *codec) char *name, int namelen) { { const struct hda_vendor_id *c; const struct hda_vendor_id *c; const char *vendor = NULL; const char *vendor = NULL; u16 vendor_id = codec->vendor_id >> 16; u16 vendor_id = codec->vendor_id >> 16; char tmp[16]; char tmp[16], name[32]; for (c = hda_vendor_ids; c->id; c++) { for (c = hda_vendor_ids; c->id; c++) { if (c->id == vendor_id) { if (c->id == vendor_id) { Loading @@ -502,10 +562,15 @@ void snd_hda_get_codec_name(struct hda_codec *codec, vendor = tmp; vendor = tmp; } } if (codec->preset && codec->preset->name) if (codec->preset && codec->preset->name) snprintf(name, namelen, "%s %s", vendor, codec->preset->name); snprintf(name, sizeof(name), "%s %s", vendor, codec->preset->name); else else snprintf(name, namelen, "%s ID %x", vendor, snprintf(name, sizeof(name), "%s ID %x", vendor, codec->vendor_id & 0xffff); codec->vendor_id & 0xffff); codec->name = kstrdup(name, GFP_KERNEL); if (!codec->name) return -ENOMEM; return 0; } } /* /* Loading Loading @@ -570,11 +635,14 @@ static void snd_hda_codec_free(struct hda_codec *codec) flush_scheduled_work(); flush_scheduled_work(); #endif #endif list_del(&codec->list); list_del(&codec->list); snd_array_free(&codec->mixers); codec->bus->caddr_tbl[codec->addr] = NULL; codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) if (codec->patch_ops.free) codec->patch_ops.free(codec); codec->patch_ops.free(codec); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); free_hda_cache(&codec->cmd_cache); kfree(codec->name); kfree(codec->modelname); kfree(codec->wcaps); kfree(codec->wcaps); kfree(codec); kfree(codec); } } Loading Loading @@ -616,6 +684,14 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, mutex_init(&codec->spdif_mutex); mutex_init(&codec->spdif_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { snd_hda_codec_free(codec); return -ENODEV; } } #ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE INIT_DELAYED_WORK(&codec->power_work, hda_power_work); INIT_DELAYED_WORK(&codec->power_work, hda_power_work); Loading Loading @@ -661,12 +737,41 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, snd_hda_codec_read(codec, nid, 0, snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_SUBSYSTEM_ID, 0); AC_VERB_GET_SUBSYSTEM_ID, 0); } } if (bus->modelname) codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); err = snd_hda_codec_configure(codec); if (err < 0) { snd_hda_codec_free(codec); return err; } snd_hda_codec_proc_new(codec); snd_hda_create_hwdep(codec); sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component); if (codecp) *codecp = codec; return 0; } int snd_hda_codec_configure(struct hda_codec *codec) { int err; codec->preset = find_codec_preset(codec); codec->preset = find_codec_preset(codec); if (!codec->name) { err = get_codec_name(codec); if (err < 0) return err; } /* audio codec should override the mixer name */ /* audio codec should override the mixer name */ if (codec->afg || !*bus->card->mixername) if (codec->afg || !*codec->bus->card->mixername) snd_hda_get_codec_name(codec, bus->card->mixername, strlcpy(codec->bus->card->mixername, codec->name, sizeof(bus->card->mixername)); sizeof(codec->bus->card->mixername)); if (is_generic_config(codec)) { if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); err = snd_hda_parse_generic_codec(codec); Loading @@ -683,27 +788,11 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, printk(KERN_ERR "hda-codec: No codec parser is available\n"); printk(KERN_ERR "hda-codec: No codec parser is available\n"); patched: patched: if (err < 0) { if (!err && codec->patch_ops.unsol_event) snd_hda_codec_free(codec); err = init_unsol_queue(codec->bus); return err; return err; } } if (codec->patch_ops.unsol_event) init_unsol_queue(bus); snd_hda_codec_proc_new(codec); #ifdef CONFIG_SND_HDA_HWDEP snd_hda_create_hwdep(codec); #endif sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component); if (codecp) *codecp = codec; return 0; } /** /** * snd_hda_codec_setup_stream - set up the codec for streaming * snd_hda_codec_setup_stream - set up the codec for streaming * @codec: the CODEC to set up * @codec: the CODEC to set up Loading Loading @@ -756,12 +845,12 @@ static void __devinit init_hda_cache(struct hda_cache_rec *cache, { { memset(cache, 0, sizeof(*cache)); memset(cache, 0, sizeof(*cache)); memset(cache->hash, 0xff, sizeof(cache->hash)); memset(cache->hash, 0xff, sizeof(cache->hash)); cache->record_size = record_size; snd_array_init(&cache->buf, record_size, 64); } } static void free_hda_cache(struct hda_cache_rec *cache) static void free_hda_cache(struct hda_cache_rec *cache) { { kfree(cache->buffer); snd_array_free(&cache->buf); } } /* query the hash. allocate an entry if not found. */ /* query the hash. allocate an entry if not found. */ Loading @@ -770,38 +859,18 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, { { u16 idx = key % (u16)ARRAY_SIZE(cache->hash); u16 idx = key % (u16)ARRAY_SIZE(cache->hash); u16 cur = cache->hash[idx]; u16 cur = cache->hash[idx]; struct hda_cache_head *info_head = cache->buf.list; struct hda_cache_head *info; struct hda_cache_head *info; while (cur != 0xffff) { while (cur != 0xffff) { info = (struct hda_cache_head *)(cache->buffer + info = &info_head[cur]; cur * cache->record_size); if (info->key == key) if (info->key == key) return info; return info; cur = info->next; cur = info->next; } } /* add a new hash entry */ /* add a new hash entry */ if (cache->num_entries >= cache->size) { info = snd_array_new(&cache->buf); /* reallocate the array */ unsigned int new_size = cache->size + 64; void *new_buffer; new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); if (!new_buffer) { snd_printk(KERN_ERR "hda_codec: " "can't malloc amp_info\n"); return NULL; } if (cache->buffer) { memcpy(new_buffer, cache->buffer, cache->size * cache->record_size); kfree(cache->buffer); } cache->size = new_size; cache->buffer = new_buffer; } cur = cache->num_entries++; info = (struct hda_cache_head *)(cache->buffer + cur * cache->record_size); info->key = key; info->key = key; info->val = 0; info->val = 0; info->next = cache->hash[idx]; info->next = cache->hash[idx]; Loading Loading @@ -942,10 +1011,10 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, /* resume the all amp commands from the cache */ /* resume the all amp commands from the cache */ void snd_hda_codec_resume_amp(struct hda_codec *codec) void snd_hda_codec_resume_amp(struct hda_codec *codec) { { struct hda_amp_info *buffer = codec->amp_cache.buffer; struct hda_amp_info *buffer = codec->amp_cache.buf.list; int i; int i; for (i = 0; i < codec->amp_cache.size; i++, buffer++) { for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) { u32 key = buffer->head.key; u32 key = buffer->head.key; hda_nid_t nid; hda_nid_t nid; unsigned int idx, dir, ch; unsigned int idx, dir, ch; Loading Loading @@ -1097,6 +1166,57 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, return _snd_hda_find_mixer_ctl(codec, name, 0); return _snd_hda_find_mixer_ctl(codec, name, 0); } } /* Add a control element and assign to the codec */ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) { int err; struct snd_kcontrol **knewp; err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; knewp = snd_array_new(&codec->mixers); if (!knewp) return -ENOMEM; *knewp = kctl; return 0; } /* Clear all controls assigned to the given codec */ void snd_hda_ctls_clear(struct hda_codec *codec) { int i; struct snd_kcontrol **kctls = codec->mixers.list; for (i = 0; i < codec->mixers.used; i++) snd_ctl_remove(codec->bus->card, kctls[i]); snd_array_free(&codec->mixers); } void snd_hda_codec_reset(struct hda_codec *codec) { int i; #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); flush_scheduled_work(); #endif snd_hda_ctls_clear(codec); /* relase PCMs */ for (i = 0; i < codec->num_pcms; i++) { if (codec->pcm_info[i].pcm) snd_device_free(codec->bus->card, codec->pcm_info[i].pcm); } if (codec->patch_ops.free) codec->patch_ops.free(codec); codec->spec = NULL; free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; } /* create a virtual master control and add slaves */ /* create a virtual master control and add slaves */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves) unsigned int *tlv, const char **slaves) Loading @@ -1114,7 +1234,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, kctl = snd_ctl_make_virtual_master(name, tlv); kctl = snd_ctl_make_virtual_master(name, tlv); if (!kctl) if (!kctl) return -ENOMEM; return -ENOMEM; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) if (err < 0) return err; return err; Loading Loading @@ -1578,7 +1698,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) kctl = snd_ctl_new1(dig_mix, codec); kctl = snd_ctl_new1(dig_mix, codec); kctl->id.index = idx; kctl->id.index = idx; kctl->private_value = nid; kctl->private_value = nid; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) if (err < 0) return err; return err; } } Loading Loading @@ -1622,7 +1742,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, if (!mout->dig_out_nid) if (!mout->dig_out_nid) return 0; return 0; /* ATTENTION: here mout is passed as private_data, instead of codec */ /* ATTENTION: here mout is passed as private_data, instead of codec */ return snd_ctl_add(codec->bus->card, return snd_hda_ctl_add(codec, snd_ctl_new1(&spdif_share_sw, mout)); snd_ctl_new1(&spdif_share_sw, mout)); } } Loading Loading @@ -1724,7 +1844,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); kctl = snd_ctl_new1(dig_mix, codec); kctl->private_value = nid; kctl->private_value = nid; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) if (err < 0) return err; return err; } } Loading Loading @@ -1779,10 +1899,10 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, /* resume the all commands from the cache */ /* resume the all commands from the cache */ void snd_hda_codec_resume_cache(struct hda_codec *codec) void snd_hda_codec_resume_cache(struct hda_codec *codec) { { struct hda_cache_head *buffer = codec->cmd_cache.buffer; struct hda_cache_head *buffer = codec->cmd_cache.buf.list; int i; int i; for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) { u32 key = buffer->key; u32 key = buffer->key; if (!key) if (!key) continue; continue; Loading Loading @@ -1867,6 +1987,17 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, } } } } #ifdef CONFIG_SND_HDA_HWDEP /* execute additional init verbs */ static void hda_exec_init_verbs(struct hda_codec *codec) { if (codec->init_verbs.list) snd_hda_sequence_write(codec, codec->init_verbs.list); } #else static inline void hda_exec_init_verbs(struct hda_codec *codec) {} #endif #ifdef SND_HDA_NEEDS_RESUME #ifdef SND_HDA_NEEDS_RESUME /* /* * call suspend and power-down; used both from PM and power-save * call suspend and power-down; used both from PM and power-save Loading @@ -1893,6 +2024,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_set_power_state(codec, hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); AC_PWRST_D0); hda_exec_init_verbs(codec); if (codec->patch_ops.resume) if (codec->patch_ops.resume) codec->patch_ops.resume(codec); codec->patch_ops.resume(codec); else { else { Loading @@ -1918,6 +2050,15 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) struct hda_codec *codec; struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { list_for_each_entry(codec, &bus->codec_list, list) { int err = snd_hda_codec_build_controls(codec); if (err < 0) return err; } return 0; } int snd_hda_codec_build_controls(struct hda_codec *codec) { int err = 0; int err = 0; /* fake as if already powered-on */ /* fake as if already powered-on */ hda_keep_power_on(codec); hda_keep_power_on(codec); Loading @@ -1925,6 +2066,7 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) hda_set_power_state(codec, hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); AC_PWRST_D0); hda_exec_init_verbs(codec); /* continue to initialize... */ /* continue to initialize... */ if (codec->patch_ops.init) if (codec->patch_ops.init) err = codec->patch_ops.init(codec); err = codec->patch_ops.init(codec); Loading @@ -1933,8 +2075,6 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) snd_hda_power_down(codec); snd_hda_power_down(codec); if (err < 0) if (err < 0) return err; return err; } return 0; return 0; } } Loading Loading @@ -2235,7 +2375,7 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, return 0; return 0; } } static int __devinit set_pcm_default_values(struct hda_codec *codec, static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream *info) struct hda_pcm_stream *info) { { /* query support PCM information from the given NID */ /* query support PCM information from the given NID */ Loading @@ -2262,6 +2402,28 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, return 0; return 0; } } /* * attach a new PCM stream */ static int __devinit snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) { struct hda_pcm_stream *info; int stream, err; if (!pcm->name) return -EINVAL; for (stream = 0; stream < 2; stream++) { info = &pcm->stream[stream]; if (info->substreams) { err = set_pcm_default_values(codec, info); if (err < 0) return err; } } return codec->bus->ops.attach_pcm(codec, pcm); } /** /** * snd_hda_build_pcms - build PCM information * snd_hda_build_pcms - build PCM information * @bus: the BUS * @bus: the BUS Loading @@ -2288,25 +2450,67 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, * * * This function returns 0 if successfull, or a negative error code. * This function returns 0 if successfull, or a negative error code. */ */ int __devinit snd_hda_build_pcms(struct hda_bus *bus) int snd_hda_build_pcms(struct hda_bus *bus) { { 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 }; /* normal audio device indices; not linear to keep compatibility */ static int audio_idx[4] = { 0, 2, 4, 5 }; struct hda_codec *codec; struct hda_codec *codec; int num_devs[HDA_PCM_NTYPES]; memset(num_devs, 0, sizeof(num_devs)); list_for_each_entry(codec, &bus->codec_list, list) { list_for_each_entry(codec, &bus->codec_list, list) { unsigned int pcm, s; unsigned int pcm; int err; int err; if (!codec->num_pcms) { if (!codec->patch_ops.build_pcms) if (!codec->patch_ops.build_pcms) continue; continue; err = codec->patch_ops.build_pcms(codec); err = codec->patch_ops.build_pcms(codec); if (err < 0) if (err < 0) return err; return err; } for (pcm = 0; pcm < codec->num_pcms; pcm++) { for (pcm = 0; pcm < codec->num_pcms; pcm++) { for (s = 0; s < 2; s++) { struct hda_pcm *cpcm = &codec->pcm_info[pcm]; struct hda_pcm_stream *info; int type = cpcm->pcm_type; info = &codec->pcm_info[pcm].stream[s]; int dev; if (!info->substreams) switch (type) { case HDA_PCM_TYPE_AUDIO: if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { snd_printk(KERN_WARNING "Too many audio devices\n"); continue; continue; err = set_pcm_default_values(codec, info); } dev = audio_idx[num_devs[type]]; break; case HDA_PCM_TYPE_SPDIF: case HDA_PCM_TYPE_HDMI: case HDA_PCM_TYPE_MODEM: if (num_devs[type]) { snd_printk(KERN_WARNING "%s already defined\n", dev_name[type]); continue; } dev = dev_idx[type]; break; default: snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); continue; } num_devs[type]++; if (!cpcm->pcm) { cpcm->device = dev; err = snd_hda_attach_pcm(codec, cpcm); if (err < 0) if (err < 0) return err; return err; } } Loading @@ -2332,11 +2536,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, const char **models, int num_configs, const char **models, const struct snd_pci_quirk *tbl) const struct snd_pci_quirk *tbl) { { if (codec->bus->modelname && models) { if (codec->modelname && models) { int i; int i; for (i = 0; i < num_configs; i++) { for (i = 0; i < num_configs; i++) { if (models[i] && if (models[i] && !strcmp(codec->bus->modelname, models[i])) { !strcmp(codec->modelname, models[i])) { snd_printd(KERN_INFO "hda_codec: model '%s' is " snd_printd(KERN_INFO "hda_codec: model '%s' is " "selected\n", models[i]); "selected\n", models[i]); return i; return i; Loading Loading @@ -2389,7 +2593,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) kctl = snd_ctl_new1(knew, codec); kctl = snd_ctl_new1(knew, codec); if (!kctl) if (!kctl) return -ENOMEM; return -ENOMEM; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) { if (err < 0) { if (!codec->addr) if (!codec->addr) return err; return err; Loading @@ -2397,7 +2601,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) if (!kctl) if (!kctl) return -ENOMEM; return -ENOMEM; kctl->id.device = codec->addr; kctl->id.device = codec->addr; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) if (err < 0) return err; return err; } } Loading Loading @@ -3138,3 +3342,37 @@ int snd_hda_codecs_inuse(struct hda_bus *bus) } } #endif #endif #endif #endif /* * generic arrays */ /* get a new element from the given array * if it exceeds the pre-allocated array size, re-allocate the array */ void *snd_array_new(struct snd_array *array) { if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; void *nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); if (!nlist) return NULL; if (array->list) { memcpy(nlist, array->list, array->elem_size * array->alloced); kfree(array->list); } array->list = nlist; array->alloced = num; } return array->list + (array->used++ * array->elem_size); } /* free the given array elements */ void snd_array_free(struct snd_array *array) { kfree(array->list); array->used = 0; array->alloced = 0; array->list = NULL; }