{ 0x1002, "ATI" },
{ 0x1057, "Motorola" },
{ 0x1095, "Silicon Image" },
+ { 0x10de, "Nvidia" },
{ 0x10ec, "Realtek" },
{ 0x1106, "VIA" },
{ 0x111d, "IDT" },
{ 0x1854, "LG" },
{ 0x1aec, "Wolfson Microelectronics" },
{ 0x434d, "C-Media" },
+ { 0x8086, "Intel" },
{ 0x8384, "SigmaTel" },
{} /* terminator */
};
unsol->queue[wp] = res;
unsol->queue[wp + 1] = res_ex;
- schedule_work(&unsol->work);
+ queue_work(bus->workq, &unsol->work);
return 0;
}
if (!bus)
return 0;
- if (bus->unsol) {
- flush_scheduled_work();
+ if (bus->workq)
+ flush_workqueue(bus->workq);
+ if (bus->unsol)
kfree(bus->unsol);
- }
list_for_each_entry_safe(codec, n, &bus->codec_list, list) {
snd_hda_codec_free(codec);
}
if (bus->ops.private_free)
bus->ops.private_free(bus);
+ if (bus->workq)
+ destroy_workqueue(bus->workq);
kfree(bus);
return 0;
}
{
struct hda_bus *bus;
int err;
+ char qname[8];
static struct snd_device_ops dev_ops = {
.dev_register = snd_hda_bus_dev_register,
.dev_free = snd_hda_bus_dev_free,
mutex_init(&bus->cmd_mutex);
INIT_LIST_HEAD(&bus->codec_list);
+ snprintf(qname, sizeof(qname), "hda%d", card->number);
+ bus->workq = create_workqueue(qname);
+ if (!bus->workq) {
+ snd_printk(KERN_ERR "cannot create workqueue %s\n", qname);
+ kfree(bus);
+ return -ENOMEM;
+ }
+
err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops);
if (err < 0) {
snd_hda_bus_free(bus);
return;
#ifdef CONFIG_SND_HDA_POWER_SAVE
cancel_delayed_work(&codec->power_work);
- flush_scheduled_work();
+ flush_workqueue(codec->bus->workq);
#endif
list_del(&codec->list);
snd_array_free(&codec->mixers);
* Returns 0 if successful, or a negative error code.
*/
int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
- struct hda_codec **codecp)
+ int do_init, struct hda_codec **codecp)
{
struct hda_codec *codec;
char component[31];
codec->bus = bus;
codec->addr = codec_addr;
mutex_init(&codec->spdif_mutex);
+ 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);
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;
+ if (do_init) {
+ err = snd_hda_codec_configure(codec);
+ if (err < 0) {
+ snd_hda_codec_free(codec);
+ return err;
+ }
}
snd_hda_codec_proc_new(codec);
#ifdef CONFIG_SND_HDA_POWER_SAVE
cancel_delayed_work(&codec->power_work);
- flush_scheduled_work();
+ flush_workqueue(codec->bus->workq);
#endif
snd_hda_ctls_clear(codec);
/* relase PCMs */
}
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
+ codec->proc_widget_hook = NULL;
codec->spec = NULL;
free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache);
+ init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
+ init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
codec->num_pcms = 0;
codec->pcm_info = NULL;
codec->preset = NULL;
unsigned long pval;
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
pval = kcontrol->private_value;
kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
kcontrol->private_value = pval;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get);
unsigned long pval;
int i, indices, err = 0, change = 0;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
pval = kcontrol->private_value;
indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
for (i = 0; i < indices; i++) {
change |= err;
}
kcontrol->private_value = pval;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err < 0 ? err : change;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put);
struct hda_bind_ctls *c;
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
c = (struct hda_bind_ctls *)kcontrol->private_value;
kcontrol->private_value = *c->values;
err = c->ops->info(kcontrol, uinfo);
kcontrol->private_value = (long)c;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info);
struct hda_bind_ctls *c;
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
c = (struct hda_bind_ctls *)kcontrol->private_value;
kcontrol->private_value = *c->values;
err = c->ops->get(kcontrol, ucontrol);
kcontrol->private_value = (long)c;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get);
unsigned long *vals;
int err = 0, change = 0;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
c = (struct hda_bind_ctls *)kcontrol->private_value;
for (vals = c->values; *vals; vals++) {
kcontrol->private_value = *vals;
change |= err;
}
kcontrol->private_value = (long)c;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err < 0 ? err : change;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put);
struct hda_bind_ctls *c;
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
c = (struct hda_bind_ctls *)kcontrol->private_value;
kcontrol->private_value = *c->values;
err = c->ops->tlv(kcontrol, op_flag, size, tlv);
kcontrol->private_value = (long)c;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv);
return;
if (power_save(codec)) {
codec->power_transition = 1; /* avoid reentrance */
- schedule_delayed_work(&codec->power_work,
+ queue_delayed_work(codec->bus->workq, &codec->power_work,
msecs_to_jiffies(power_save(codec) * 1000));
}
}