diff options
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e16cf63821ae..3c596da2b9b5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -373,7 +373,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) | |||
373 | unsol->queue[wp] = res; | 373 | unsol->queue[wp] = res; |
374 | unsol->queue[wp + 1] = res_ex; | 374 | unsol->queue[wp + 1] = res_ex; |
375 | 375 | ||
376 | schedule_work(&unsol->work); | 376 | queue_work(bus->workq, &unsol->work); |
377 | 377 | ||
378 | return 0; | 378 | return 0; |
379 | } | 379 | } |
@@ -437,15 +437,17 @@ static int snd_hda_bus_free(struct hda_bus *bus) | |||
437 | 437 | ||
438 | if (!bus) | 438 | if (!bus) |
439 | return 0; | 439 | return 0; |
440 | if (bus->unsol) { | 440 | if (bus->workq) |
441 | flush_scheduled_work(); | 441 | flush_workqueue(bus->workq); |
442 | if (bus->unsol) | ||
442 | kfree(bus->unsol); | 443 | kfree(bus->unsol); |
443 | } | ||
444 | list_for_each_entry_safe(codec, n, &bus->codec_list, list) { | 444 | list_for_each_entry_safe(codec, n, &bus->codec_list, list) { |
445 | snd_hda_codec_free(codec); | 445 | snd_hda_codec_free(codec); |
446 | } | 446 | } |
447 | if (bus->ops.private_free) | 447 | if (bus->ops.private_free) |
448 | bus->ops.private_free(bus); | 448 | bus->ops.private_free(bus); |
449 | if (bus->workq) | ||
450 | destroy_workqueue(bus->workq); | ||
449 | kfree(bus); | 451 | kfree(bus); |
450 | return 0; | 452 | return 0; |
451 | } | 453 | } |
@@ -485,6 +487,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, | |||
485 | { | 487 | { |
486 | struct hda_bus *bus; | 488 | struct hda_bus *bus; |
487 | int err; | 489 | int err; |
490 | char qname[8]; | ||
488 | static struct snd_device_ops dev_ops = { | 491 | static struct snd_device_ops dev_ops = { |
489 | .dev_register = snd_hda_bus_dev_register, | 492 | .dev_register = snd_hda_bus_dev_register, |
490 | .dev_free = snd_hda_bus_dev_free, | 493 | .dev_free = snd_hda_bus_dev_free, |
@@ -514,6 +517,14 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, | |||
514 | mutex_init(&bus->cmd_mutex); | 517 | mutex_init(&bus->cmd_mutex); |
515 | INIT_LIST_HEAD(&bus->codec_list); | 518 | INIT_LIST_HEAD(&bus->codec_list); |
516 | 519 | ||
520 | snprintf(qname, sizeof(qname), "hda%d", card->number); | ||
521 | bus->workq = create_workqueue(qname); | ||
522 | if (!bus->workq) { | ||
523 | snd_printk(KERN_ERR "cannot create workqueue %s\n", qname); | ||
524 | kfree(bus); | ||
525 | return -ENOMEM; | ||
526 | } | ||
527 | |||
517 | err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); | 528 | err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); |
518 | if (err < 0) { | 529 | if (err < 0) { |
519 | snd_hda_bus_free(bus); | 530 | snd_hda_bus_free(bus); |
@@ -684,7 +695,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
684 | return; | 695 | return; |
685 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 696 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
686 | cancel_delayed_work(&codec->power_work); | 697 | cancel_delayed_work(&codec->power_work); |
687 | flush_scheduled_work(); | 698 | flush_workqueue(codec->bus->workq); |
688 | #endif | 699 | #endif |
689 | list_del(&codec->list); | 700 | list_del(&codec->list); |
690 | snd_array_free(&codec->mixers); | 701 | snd_array_free(&codec->mixers); |
@@ -735,6 +746,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr | |||
735 | codec->bus = bus; | 746 | codec->bus = bus; |
736 | codec->addr = codec_addr; | 747 | codec->addr = codec_addr; |
737 | mutex_init(&codec->spdif_mutex); | 748 | mutex_init(&codec->spdif_mutex); |
749 | mutex_init(&codec->control_mutex); | ||
738 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); | 750 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); |
739 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); | 751 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); |
740 | snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); | 752 | snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); |
@@ -1272,7 +1284,7 @@ void snd_hda_codec_reset(struct hda_codec *codec) | |||
1272 | 1284 | ||
1273 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1285 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1274 | cancel_delayed_work(&codec->power_work); | 1286 | cancel_delayed_work(&codec->power_work); |
1275 | flush_scheduled_work(); | 1287 | flush_workqueue(codec->bus->workq); |
1276 | #endif | 1288 | #endif |
1277 | snd_hda_ctls_clear(codec); | 1289 | snd_hda_ctls_clear(codec); |
1278 | /* relase PCMs */ | 1290 | /* relase PCMs */ |
@@ -1418,12 +1430,12 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, | |||
1418 | unsigned long pval; | 1430 | unsigned long pval; |
1419 | int err; | 1431 | int err; |
1420 | 1432 | ||
1421 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1433 | mutex_lock(&codec->control_mutex); |
1422 | pval = kcontrol->private_value; | 1434 | pval = kcontrol->private_value; |
1423 | kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ | 1435 | kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ |
1424 | err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); | 1436 | err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); |
1425 | kcontrol->private_value = pval; | 1437 | kcontrol->private_value = pval; |
1426 | mutex_unlock(&codec->spdif_mutex); | 1438 | mutex_unlock(&codec->control_mutex); |
1427 | return err; | 1439 | return err; |
1428 | } | 1440 | } |
1429 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); | 1441 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); |
@@ -1435,7 +1447,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, | |||
1435 | unsigned long pval; | 1447 | unsigned long pval; |
1436 | int i, indices, err = 0, change = 0; | 1448 | int i, indices, err = 0, change = 0; |
1437 | 1449 | ||
1438 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1450 | mutex_lock(&codec->control_mutex); |
1439 | pval = kcontrol->private_value; | 1451 | pval = kcontrol->private_value; |
1440 | indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; | 1452 | indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; |
1441 | for (i = 0; i < indices; i++) { | 1453 | for (i = 0; i < indices; i++) { |
@@ -1447,7 +1459,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, | |||
1447 | change |= err; | 1459 | change |= err; |
1448 | } | 1460 | } |
1449 | kcontrol->private_value = pval; | 1461 | kcontrol->private_value = pval; |
1450 | mutex_unlock(&codec->spdif_mutex); | 1462 | mutex_unlock(&codec->control_mutex); |
1451 | return err < 0 ? err : change; | 1463 | return err < 0 ? err : change; |
1452 | } | 1464 | } |
1453 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); | 1465 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); |
@@ -1462,12 +1474,12 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, | |||
1462 | struct hda_bind_ctls *c; | 1474 | struct hda_bind_ctls *c; |
1463 | int err; | 1475 | int err; |
1464 | 1476 | ||
1465 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1477 | mutex_lock(&codec->control_mutex); |
1466 | c = (struct hda_bind_ctls *)kcontrol->private_value; | 1478 | c = (struct hda_bind_ctls *)kcontrol->private_value; |
1467 | kcontrol->private_value = *c->values; | 1479 | kcontrol->private_value = *c->values; |
1468 | err = c->ops->info(kcontrol, uinfo); | 1480 | err = c->ops->info(kcontrol, uinfo); |
1469 | kcontrol->private_value = (long)c; | 1481 | kcontrol->private_value = (long)c; |
1470 | mutex_unlock(&codec->spdif_mutex); | 1482 | mutex_unlock(&codec->control_mutex); |
1471 | return err; | 1483 | return err; |
1472 | } | 1484 | } |
1473 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); | 1485 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); |
@@ -1479,12 +1491,12 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, | |||
1479 | struct hda_bind_ctls *c; | 1491 | struct hda_bind_ctls *c; |
1480 | int err; | 1492 | int err; |
1481 | 1493 | ||
1482 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1494 | mutex_lock(&codec->control_mutex); |
1483 | c = (struct hda_bind_ctls *)kcontrol->private_value; | 1495 | c = (struct hda_bind_ctls *)kcontrol->private_value; |
1484 | kcontrol->private_value = *c->values; | 1496 | kcontrol->private_value = *c->values; |
1485 | err = c->ops->get(kcontrol, ucontrol); | 1497 | err = c->ops->get(kcontrol, ucontrol); |
1486 | kcontrol->private_value = (long)c; | 1498 | kcontrol->private_value = (long)c; |
1487 | mutex_unlock(&codec->spdif_mutex); | 1499 | mutex_unlock(&codec->control_mutex); |
1488 | return err; | 1500 | return err; |
1489 | } | 1501 | } |
1490 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); | 1502 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); |
@@ -1497,7 +1509,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, | |||
1497 | unsigned long *vals; | 1509 | unsigned long *vals; |
1498 | int err = 0, change = 0; | 1510 | int err = 0, change = 0; |
1499 | 1511 | ||
1500 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1512 | mutex_lock(&codec->control_mutex); |
1501 | c = (struct hda_bind_ctls *)kcontrol->private_value; | 1513 | c = (struct hda_bind_ctls *)kcontrol->private_value; |
1502 | for (vals = c->values; *vals; vals++) { | 1514 | for (vals = c->values; *vals; vals++) { |
1503 | kcontrol->private_value = *vals; | 1515 | kcontrol->private_value = *vals; |
@@ -1507,7 +1519,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, | |||
1507 | change |= err; | 1519 | change |= err; |
1508 | } | 1520 | } |
1509 | kcontrol->private_value = (long)c; | 1521 | kcontrol->private_value = (long)c; |
1510 | mutex_unlock(&codec->spdif_mutex); | 1522 | mutex_unlock(&codec->control_mutex); |
1511 | return err < 0 ? err : change; | 1523 | return err < 0 ? err : change; |
1512 | } | 1524 | } |
1513 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); | 1525 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); |
@@ -1519,12 +1531,12 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
1519 | struct hda_bind_ctls *c; | 1531 | struct hda_bind_ctls *c; |
1520 | int err; | 1532 | int err; |
1521 | 1533 | ||
1522 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1534 | mutex_lock(&codec->control_mutex); |
1523 | c = (struct hda_bind_ctls *)kcontrol->private_value; | 1535 | c = (struct hda_bind_ctls *)kcontrol->private_value; |
1524 | kcontrol->private_value = *c->values; | 1536 | kcontrol->private_value = *c->values; |
1525 | err = c->ops->tlv(kcontrol, op_flag, size, tlv); | 1537 | err = c->ops->tlv(kcontrol, op_flag, size, tlv); |
1526 | kcontrol->private_value = (long)c; | 1538 | kcontrol->private_value = (long)c; |
1527 | mutex_unlock(&codec->spdif_mutex); | 1539 | mutex_unlock(&codec->control_mutex); |
1528 | return err; | 1540 | return err; |
1529 | } | 1541 | } |
1530 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); | 1542 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); |