diff options
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 122 |
1 files changed, 103 insertions, 19 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e16cf63821a..d03f99298be 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 | } |
@@ -514,6 +516,16 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, | |||
514 | mutex_init(&bus->cmd_mutex); | 516 | mutex_init(&bus->cmd_mutex); |
515 | INIT_LIST_HEAD(&bus->codec_list); | 517 | INIT_LIST_HEAD(&bus->codec_list); |
516 | 518 | ||
519 | snprintf(bus->workq_name, sizeof(bus->workq_name), | ||
520 | "hd-audio%d", card->number); | ||
521 | bus->workq = create_singlethread_workqueue(bus->workq_name); | ||
522 | if (!bus->workq) { | ||
523 | snd_printk(KERN_ERR "cannot create workqueue %s\n", | ||
524 | bus->workq_name); | ||
525 | kfree(bus); | ||
526 | return -ENOMEM; | ||
527 | } | ||
528 | |||
517 | err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); | 529 | err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); |
518 | if (err < 0) { | 530 | if (err < 0) { |
519 | snd_hda_bus_free(bus); | 531 | snd_hda_bus_free(bus); |
@@ -684,7 +696,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
684 | return; | 696 | return; |
685 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 697 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
686 | cancel_delayed_work(&codec->power_work); | 698 | cancel_delayed_work(&codec->power_work); |
687 | flush_scheduled_work(); | 699 | flush_workqueue(codec->bus->workq); |
688 | #endif | 700 | #endif |
689 | list_del(&codec->list); | 701 | list_del(&codec->list); |
690 | snd_array_free(&codec->mixers); | 702 | snd_array_free(&codec->mixers); |
@@ -735,6 +747,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr | |||
735 | codec->bus = bus; | 747 | codec->bus = bus; |
736 | codec->addr = codec_addr; | 748 | codec->addr = codec_addr; |
737 | mutex_init(&codec->spdif_mutex); | 749 | mutex_init(&codec->spdif_mutex); |
750 | mutex_init(&codec->control_mutex); | ||
738 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); | 751 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); |
739 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); | 752 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); |
740 | snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); | 753 | snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); |
@@ -1272,7 +1285,7 @@ void snd_hda_codec_reset(struct hda_codec *codec) | |||
1272 | 1285 | ||
1273 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1286 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1274 | cancel_delayed_work(&codec->power_work); | 1287 | cancel_delayed_work(&codec->power_work); |
1275 | flush_scheduled_work(); | 1288 | flush_workqueue(codec->bus->workq); |
1276 | #endif | 1289 | #endif |
1277 | snd_hda_ctls_clear(codec); | 1290 | snd_hda_ctls_clear(codec); |
1278 | /* relase PCMs */ | 1291 | /* relase PCMs */ |
@@ -1418,12 +1431,12 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, | |||
1418 | unsigned long pval; | 1431 | unsigned long pval; |
1419 | int err; | 1432 | int err; |
1420 | 1433 | ||
1421 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1434 | mutex_lock(&codec->control_mutex); |
1422 | pval = kcontrol->private_value; | 1435 | pval = kcontrol->private_value; |
1423 | kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ | 1436 | kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ |
1424 | err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); | 1437 | err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); |
1425 | kcontrol->private_value = pval; | 1438 | kcontrol->private_value = pval; |
1426 | mutex_unlock(&codec->spdif_mutex); | 1439 | mutex_unlock(&codec->control_mutex); |
1427 | return err; | 1440 | return err; |
1428 | } | 1441 | } |
1429 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); | 1442 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); |
@@ -1435,7 +1448,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, | |||
1435 | unsigned long pval; | 1448 | unsigned long pval; |
1436 | int i, indices, err = 0, change = 0; | 1449 | int i, indices, err = 0, change = 0; |
1437 | 1450 | ||
1438 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1451 | mutex_lock(&codec->control_mutex); |
1439 | pval = kcontrol->private_value; | 1452 | pval = kcontrol->private_value; |
1440 | indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; | 1453 | indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; |
1441 | for (i = 0; i < indices; i++) { | 1454 | for (i = 0; i < indices; i++) { |
@@ -1447,7 +1460,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, | |||
1447 | change |= err; | 1460 | change |= err; |
1448 | } | 1461 | } |
1449 | kcontrol->private_value = pval; | 1462 | kcontrol->private_value = pval; |
1450 | mutex_unlock(&codec->spdif_mutex); | 1463 | mutex_unlock(&codec->control_mutex); |
1451 | return err < 0 ? err : change; | 1464 | return err < 0 ? err : change; |
1452 | } | 1465 | } |
1453 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); | 1466 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); |
@@ -1462,12 +1475,12 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, | |||
1462 | struct hda_bind_ctls *c; | 1475 | struct hda_bind_ctls *c; |
1463 | int err; | 1476 | int err; |
1464 | 1477 | ||
1465 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1478 | mutex_lock(&codec->control_mutex); |
1466 | c = (struct hda_bind_ctls *)kcontrol->private_value; | 1479 | c = (struct hda_bind_ctls *)kcontrol->private_value; |
1467 | kcontrol->private_value = *c->values; | 1480 | kcontrol->private_value = *c->values; |
1468 | err = c->ops->info(kcontrol, uinfo); | 1481 | err = c->ops->info(kcontrol, uinfo); |
1469 | kcontrol->private_value = (long)c; | 1482 | kcontrol->private_value = (long)c; |
1470 | mutex_unlock(&codec->spdif_mutex); | 1483 | mutex_unlock(&codec->control_mutex); |
1471 | return err; | 1484 | return err; |
1472 | } | 1485 | } |
1473 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); | 1486 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); |
@@ -1479,12 +1492,12 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, | |||
1479 | struct hda_bind_ctls *c; | 1492 | struct hda_bind_ctls *c; |
1480 | int err; | 1493 | int err; |
1481 | 1494 | ||
1482 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1495 | mutex_lock(&codec->control_mutex); |
1483 | c = (struct hda_bind_ctls *)kcontrol->private_value; | 1496 | c = (struct hda_bind_ctls *)kcontrol->private_value; |
1484 | kcontrol->private_value = *c->values; | 1497 | kcontrol->private_value = *c->values; |
1485 | err = c->ops->get(kcontrol, ucontrol); | 1498 | err = c->ops->get(kcontrol, ucontrol); |
1486 | kcontrol->private_value = (long)c; | 1499 | kcontrol->private_value = (long)c; |
1487 | mutex_unlock(&codec->spdif_mutex); | 1500 | mutex_unlock(&codec->control_mutex); |
1488 | return err; | 1501 | return err; |
1489 | } | 1502 | } |
1490 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); | 1503 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); |
@@ -1497,7 +1510,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, | |||
1497 | unsigned long *vals; | 1510 | unsigned long *vals; |
1498 | int err = 0, change = 0; | 1511 | int err = 0, change = 0; |
1499 | 1512 | ||
1500 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1513 | mutex_lock(&codec->control_mutex); |
1501 | c = (struct hda_bind_ctls *)kcontrol->private_value; | 1514 | c = (struct hda_bind_ctls *)kcontrol->private_value; |
1502 | for (vals = c->values; *vals; vals++) { | 1515 | for (vals = c->values; *vals; vals++) { |
1503 | kcontrol->private_value = *vals; | 1516 | kcontrol->private_value = *vals; |
@@ -1507,7 +1520,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, | |||
1507 | change |= err; | 1520 | change |= err; |
1508 | } | 1521 | } |
1509 | kcontrol->private_value = (long)c; | 1522 | kcontrol->private_value = (long)c; |
1510 | mutex_unlock(&codec->spdif_mutex); | 1523 | mutex_unlock(&codec->control_mutex); |
1511 | return err < 0 ? err : change; | 1524 | return err < 0 ? err : change; |
1512 | } | 1525 | } |
1513 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); | 1526 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); |
@@ -1519,12 +1532,12 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
1519 | struct hda_bind_ctls *c; | 1532 | struct hda_bind_ctls *c; |
1520 | int err; | 1533 | int err; |
1521 | 1534 | ||
1522 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | 1535 | mutex_lock(&codec->control_mutex); |
1523 | c = (struct hda_bind_ctls *)kcontrol->private_value; | 1536 | c = (struct hda_bind_ctls *)kcontrol->private_value; |
1524 | kcontrol->private_value = *c->values; | 1537 | kcontrol->private_value = *c->values; |
1525 | err = c->ops->tlv(kcontrol, op_flag, size, tlv); | 1538 | err = c->ops->tlv(kcontrol, op_flag, size, tlv); |
1526 | kcontrol->private_value = (long)c; | 1539 | kcontrol->private_value = (long)c; |
1527 | mutex_unlock(&codec->spdif_mutex); | 1540 | mutex_unlock(&codec->control_mutex); |
1528 | return err; | 1541 | return err; |
1529 | } | 1542 | } |
1530 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); | 1543 | EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); |
@@ -2712,6 +2725,67 @@ int snd_hda_check_board_config(struct hda_codec *codec, | |||
2712 | EXPORT_SYMBOL_HDA(snd_hda_check_board_config); | 2725 | EXPORT_SYMBOL_HDA(snd_hda_check_board_config); |
2713 | 2726 | ||
2714 | /** | 2727 | /** |
2728 | * snd_hda_check_board_codec_sid_config - compare the current codec | ||
2729 | subsystem ID with the | ||
2730 | config table | ||
2731 | |||
2732 | This is important for Gateway notebooks with SB450 HDA Audio | ||
2733 | where the vendor ID of the PCI device is: | ||
2734 | ATI Technologies Inc SB450 HDA Audio [1002:437b] | ||
2735 | and the vendor/subvendor are found only at the codec. | ||
2736 | |||
2737 | * @codec: the HDA codec | ||
2738 | * @num_configs: number of config enums | ||
2739 | * @models: array of model name strings | ||
2740 | * @tbl: configuration table, terminated by null entries | ||
2741 | * | ||
2742 | * Compares the modelname or PCI subsystem id of the current codec with the | ||
2743 | * given configuration table. If a matching entry is found, returns its | ||
2744 | * config value (supposed to be 0 or positive). | ||
2745 | * | ||
2746 | * If no entries are matching, the function returns a negative value. | ||
2747 | */ | ||
2748 | int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, | ||
2749 | int num_configs, const char **models, | ||
2750 | const struct snd_pci_quirk *tbl) | ||
2751 | { | ||
2752 | const struct snd_pci_quirk *q; | ||
2753 | |||
2754 | /* Search for codec ID */ | ||
2755 | for (q = tbl; q->subvendor; q++) { | ||
2756 | unsigned long vendorid = (q->subdevice) | (q->subvendor << 16); | ||
2757 | |||
2758 | if (vendorid == codec->subsystem_id) | ||
2759 | break; | ||
2760 | } | ||
2761 | |||
2762 | if (!q->subvendor) | ||
2763 | return -1; | ||
2764 | |||
2765 | tbl = q; | ||
2766 | |||
2767 | if (tbl->value >= 0 && tbl->value < num_configs) { | ||
2768 | #ifdef CONFIG_SND_DEBUG_DETECT | ||
2769 | char tmp[10]; | ||
2770 | const char *model = NULL; | ||
2771 | if (models) | ||
2772 | model = models[tbl->value]; | ||
2773 | if (!model) { | ||
2774 | sprintf(tmp, "#%d", tbl->value); | ||
2775 | model = tmp; | ||
2776 | } | ||
2777 | snd_printdd(KERN_INFO "hda_codec: model '%s' is selected " | ||
2778 | "for config %x:%x (%s)\n", | ||
2779 | model, tbl->subvendor, tbl->subdevice, | ||
2780 | (tbl->name ? tbl->name : "Unknown device")); | ||
2781 | #endif | ||
2782 | return tbl->value; | ||
2783 | } | ||
2784 | return -1; | ||
2785 | } | ||
2786 | EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config); | ||
2787 | |||
2788 | /** | ||
2715 | * snd_hda_add_new_ctls - create controls from the array | 2789 | * snd_hda_add_new_ctls - create controls from the array |
2716 | * @codec: the HDA codec | 2790 | * @codec: the HDA codec |
2717 | * @knew: the array of struct snd_kcontrol_new | 2791 | * @knew: the array of struct snd_kcontrol_new |
@@ -2803,7 +2877,7 @@ void snd_hda_power_down(struct hda_codec *codec) | |||
2803 | return; | 2877 | return; |
2804 | if (power_save(codec)) { | 2878 | if (power_save(codec)) { |
2805 | codec->power_transition = 1; /* avoid reentrance */ | 2879 | codec->power_transition = 1; /* avoid reentrance */ |
2806 | schedule_delayed_work(&codec->power_work, | 2880 | queue_delayed_work(codec->bus->workq, &codec->power_work, |
2807 | msecs_to_jiffies(power_save(codec) * 1000)); | 2881 | msecs_to_jiffies(power_save(codec) * 1000)); |
2808 | } | 2882 | } |
2809 | } | 2883 | } |
@@ -3014,6 +3088,16 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, | |||
3014 | } | 3088 | } |
3015 | EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare); | 3089 | EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare); |
3016 | 3090 | ||
3091 | int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, | ||
3092 | struct hda_multi_out *mout) | ||
3093 | { | ||
3094 | mutex_lock(&codec->spdif_mutex); | ||
3095 | cleanup_dig_out_stream(codec, mout->dig_out_nid); | ||
3096 | mutex_unlock(&codec->spdif_mutex); | ||
3097 | return 0; | ||
3098 | } | ||
3099 | EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_cleanup); | ||
3100 | |||
3017 | /* | 3101 | /* |
3018 | * release the digital out | 3102 | * release the digital out |
3019 | */ | 3103 | */ |