diff options
author | Ian Minett <ian_minett@creativelabs.com> | 2012-12-20 21:53:39 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-01-15 11:00:45 -0500 |
commit | e90f29e44273867392d9d1e0fd94bbe7bffe0335 (patch) | |
tree | c0865c842b0c8a1797c501e2999909a6db71ef72 /sound/pci | |
parent | 44f0c9782cc6ab71ea947f8f710a46f2078a151c (diff) |
ALSA: hda/ca0132: Code shuffle to group similar functions.
Signed-off-by: Ian Minett <ian_minett@creativelabs.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/patch_ca0132.c | 375 |
1 files changed, 188 insertions, 187 deletions
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index c1391f43cc61..77903a398289 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c | |||
@@ -2684,41 +2684,6 @@ static bool dspload_wait_loaded(struct hda_codec *codec) | |||
2684 | } | 2684 | } |
2685 | 2685 | ||
2686 | /* | 2686 | /* |
2687 | * Controls stuffs. | ||
2688 | */ | ||
2689 | |||
2690 | /* | ||
2691 | * Mixer controls helpers. | ||
2692 | */ | ||
2693 | #define CA0132_CODEC_VOL_MONO(xname, nid, channel, dir) \ | ||
2694 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2695 | .name = xname, \ | ||
2696 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ | ||
2697 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
2698 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
2699 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | ||
2700 | .info = ca0132_volume_info, \ | ||
2701 | .get = ca0132_volume_get, \ | ||
2702 | .put = ca0132_volume_put, \ | ||
2703 | .tlv = { .c = ca0132_volume_tlv }, \ | ||
2704 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } | ||
2705 | |||
2706 | #define CA0132_CODEC_MUTE_MONO(xname, nid, channel, dir) \ | ||
2707 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2708 | .name = xname, \ | ||
2709 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ | ||
2710 | .info = snd_hda_mixer_amp_switch_info, \ | ||
2711 | .get = ca0132_switch_get, \ | ||
2712 | .put = ca0132_switch_put, \ | ||
2713 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } | ||
2714 | |||
2715 | /* stereo */ | ||
2716 | #define CA0132_CODEC_VOL(xname, nid, dir) \ | ||
2717 | CA0132_CODEC_VOL_MONO(xname, nid, 3, dir) | ||
2718 | #define CA0132_CODEC_MUTE(xname, nid, dir) \ | ||
2719 | CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir) | ||
2720 | |||
2721 | /* | ||
2722 | * PCM stuffs | 2687 | * PCM stuffs |
2723 | */ | 2688 | */ |
2724 | static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid, | 2689 | static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid, |
@@ -2875,6 +2840,41 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
2875 | return 0; | 2840 | return 0; |
2876 | } | 2841 | } |
2877 | 2842 | ||
2843 | /* | ||
2844 | * Controls stuffs. | ||
2845 | */ | ||
2846 | |||
2847 | /* | ||
2848 | * Mixer controls helpers. | ||
2849 | */ | ||
2850 | #define CA0132_CODEC_VOL_MONO(xname, nid, channel, dir) \ | ||
2851 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2852 | .name = xname, \ | ||
2853 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ | ||
2854 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
2855 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
2856 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | ||
2857 | .info = ca0132_volume_info, \ | ||
2858 | .get = ca0132_volume_get, \ | ||
2859 | .put = ca0132_volume_put, \ | ||
2860 | .tlv = { .c = ca0132_volume_tlv }, \ | ||
2861 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } | ||
2862 | |||
2863 | #define CA0132_CODEC_MUTE_MONO(xname, nid, channel, dir) \ | ||
2864 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2865 | .name = xname, \ | ||
2866 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ | ||
2867 | .info = snd_hda_mixer_amp_switch_info, \ | ||
2868 | .get = ca0132_switch_get, \ | ||
2869 | .put = ca0132_switch_put, \ | ||
2870 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } | ||
2871 | |||
2872 | /* stereo */ | ||
2873 | #define CA0132_CODEC_VOL(xname, nid, dir) \ | ||
2874 | CA0132_CODEC_VOL_MONO(xname, nid, 3, dir) | ||
2875 | #define CA0132_CODEC_MUTE(xname, nid, dir) \ | ||
2876 | CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir) | ||
2877 | |||
2878 | /* The followings are for tuning of products */ | 2878 | /* The followings are for tuning of products */ |
2879 | #ifdef ENABLE_TUNING_CONTROLS | 2879 | #ifdef ENABLE_TUNING_CONTROLS |
2880 | 2880 | ||
@@ -3959,7 +3959,70 @@ static struct snd_kcontrol_new ca0132_mixer[] = { | |||
3959 | { } /* end */ | 3959 | { } /* end */ |
3960 | }; | 3960 | }; |
3961 | 3961 | ||
3962 | static int ca0132_build_controls(struct hda_codec *codec) | ||
3963 | { | ||
3964 | struct ca0132_spec *spec = codec->spec; | ||
3965 | int i, num_fx; | ||
3966 | int err = 0; | ||
3967 | |||
3968 | /* Add Mixer controls */ | ||
3969 | for (i = 0; i < spec->num_mixers; i++) { | ||
3970 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | ||
3971 | if (err < 0) | ||
3972 | return err; | ||
3973 | } | ||
3974 | |||
3975 | /* Add in and out effects controls. | ||
3976 | * VoiceFX, PE and CrystalVoice are added separately. | ||
3977 | */ | ||
3978 | num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; | ||
3979 | for (i = 0; i < num_fx; i++) { | ||
3980 | err = add_fx_switch(codec, ca0132_effects[i].nid, | ||
3981 | ca0132_effects[i].name, | ||
3982 | ca0132_effects[i].direct); | ||
3983 | if (err < 0) | ||
3984 | return err; | ||
3985 | } | ||
3986 | |||
3987 | err = add_fx_switch(codec, PLAY_ENHANCEMENT, "PlayEnhancement", 0); | ||
3988 | if (err < 0) | ||
3989 | return err; | ||
3990 | |||
3991 | err = add_fx_switch(codec, CRYSTAL_VOICE, "CrystalVoice", 1); | ||
3992 | if (err < 0) | ||
3993 | return err; | ||
3994 | |||
3995 | add_voicefx(codec); | ||
3996 | |||
3997 | #ifdef ENABLE_TUNING_CONTROLS | ||
3998 | add_tuning_ctls(codec); | ||
3999 | #endif | ||
4000 | |||
4001 | err = snd_hda_jack_add_kctls(codec, &spec->autocfg); | ||
4002 | if (err < 0) | ||
4003 | return err; | ||
4004 | |||
4005 | if (spec->dig_out) { | ||
4006 | err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, | ||
4007 | spec->dig_out); | ||
4008 | if (err < 0) | ||
4009 | return err; | ||
4010 | err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); | ||
4011 | if (err < 0) | ||
4012 | return err; | ||
4013 | /* spec->multiout.share_spdif = 1; */ | ||
4014 | } | ||
4015 | |||
4016 | if (spec->dig_in) { | ||
4017 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); | ||
4018 | if (err < 0) | ||
4019 | return err; | ||
4020 | } | ||
4021 | return 0; | ||
4022 | } | ||
4023 | |||
3962 | /* | 4024 | /* |
4025 | * PCM | ||
3963 | */ | 4026 | */ |
3964 | static struct hda_pcm_stream ca0132_pcm_analog_playback = { | 4027 | static struct hda_pcm_stream ca0132_pcm_analog_playback = { |
3965 | .substreams = 1, | 4028 | .substreams = 1, |
@@ -4052,68 +4115,6 @@ static int ca0132_build_pcms(struct hda_codec *codec) | |||
4052 | return 0; | 4115 | return 0; |
4053 | } | 4116 | } |
4054 | 4117 | ||
4055 | static int ca0132_build_controls(struct hda_codec *codec) | ||
4056 | { | ||
4057 | struct ca0132_spec *spec = codec->spec; | ||
4058 | int i, num_fx; | ||
4059 | int err = 0; | ||
4060 | |||
4061 | /* Add Mixer controls */ | ||
4062 | for (i = 0; i < spec->num_mixers; i++) { | ||
4063 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | ||
4064 | if (err < 0) | ||
4065 | return err; | ||
4066 | } | ||
4067 | |||
4068 | /* Add in and out effects controls. | ||
4069 | * VoiceFX, PE and CrystalVoice are added separately. | ||
4070 | */ | ||
4071 | num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; | ||
4072 | for (i = 0; i < num_fx; i++) { | ||
4073 | err = add_fx_switch(codec, ca0132_effects[i].nid, | ||
4074 | ca0132_effects[i].name, | ||
4075 | ca0132_effects[i].direct); | ||
4076 | if (err < 0) | ||
4077 | return err; | ||
4078 | } | ||
4079 | |||
4080 | err = add_fx_switch(codec, PLAY_ENHANCEMENT, "PlayEnhancement", 0); | ||
4081 | if (err < 0) | ||
4082 | return err; | ||
4083 | |||
4084 | err = add_fx_switch(codec, CRYSTAL_VOICE, "CrystalVoice", 1); | ||
4085 | if (err < 0) | ||
4086 | return err; | ||
4087 | |||
4088 | add_voicefx(codec); | ||
4089 | |||
4090 | #ifdef ENABLE_TUNING_CONTROLS | ||
4091 | add_tuning_ctls(codec); | ||
4092 | #endif | ||
4093 | |||
4094 | err = snd_hda_jack_add_kctls(codec, &spec->autocfg); | ||
4095 | if (err < 0) | ||
4096 | return err; | ||
4097 | |||
4098 | if (spec->dig_out) { | ||
4099 | err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, | ||
4100 | spec->dig_out); | ||
4101 | if (err < 0) | ||
4102 | return err; | ||
4103 | err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); | ||
4104 | if (err < 0) | ||
4105 | return err; | ||
4106 | /* spec->multiout.share_spdif = 1; */ | ||
4107 | } | ||
4108 | |||
4109 | if (spec->dig_in) { | ||
4110 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); | ||
4111 | if (err < 0) | ||
4112 | return err; | ||
4113 | } | ||
4114 | return 0; | ||
4115 | } | ||
4116 | |||
4117 | static void ca0132_init_unsol(struct hda_codec *codec) | 4118 | static void ca0132_init_unsol(struct hda_codec *codec) |
4118 | { | 4119 | { |
4119 | snd_hda_jack_detect_enable(codec, UNSOL_TAG_HP, UNSOL_TAG_HP); | 4120 | snd_hda_jack_detect_enable(codec, UNSOL_TAG_HP, UNSOL_TAG_HP); |
@@ -4330,6 +4331,55 @@ static void ca0132_init_params(struct hda_codec *codec) | |||
4330 | chipio_set_control_param(codec, CONTROL_PARAM_PORTD_160OHM_GAIN, 6); | 4331 | chipio_set_control_param(codec, CONTROL_PARAM_PORTD_160OHM_GAIN, 6); |
4331 | } | 4332 | } |
4332 | 4333 | ||
4334 | static void ca0132_set_dsp_msr(struct hda_codec *codec, bool is96k) | ||
4335 | { | ||
4336 | chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, is96k); | ||
4337 | chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, is96k); | ||
4338 | chipio_set_control_flag(codec, CONTROL_FLAG_SRC_RATE_96KHZ, is96k); | ||
4339 | chipio_set_control_flag(codec, CONTROL_FLAG_SRC_CLOCK_196MHZ, is96k); | ||
4340 | chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, is96k); | ||
4341 | chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_96KHZ, is96k); | ||
4342 | |||
4343 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000); | ||
4344 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000); | ||
4345 | chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000); | ||
4346 | } | ||
4347 | |||
4348 | static bool ca0132_download_dsp_images(struct hda_codec *codec) | ||
4349 | { | ||
4350 | bool dsp_loaded = false; | ||
4351 | const struct dsp_image_seg *dsp_os_image; | ||
4352 | |||
4353 | if (request_firmware_cached(&fw_efx, EFX_FILE, | ||
4354 | codec->bus->card->dev) != 0) | ||
4355 | return false; | ||
4356 | |||
4357 | dsp_os_image = (struct dsp_image_seg *)(fw_efx->data); | ||
4358 | dspload_image(codec, dsp_os_image, 0, 0, true, 0); | ||
4359 | dsp_loaded = dspload_wait_loaded(codec); | ||
4360 | |||
4361 | return dsp_loaded; | ||
4362 | } | ||
4363 | |||
4364 | static void ca0132_download_dsp(struct hda_codec *codec) | ||
4365 | { | ||
4366 | struct ca0132_spec *spec = codec->spec; | ||
4367 | |||
4368 | spec->dsp_state = DSP_DOWNLOAD_INIT; | ||
4369 | |||
4370 | if (spec->dsp_state == DSP_DOWNLOAD_INIT) { | ||
4371 | chipio_enable_clocks(codec); | ||
4372 | spec->dsp_state = DSP_DOWNLOADING; | ||
4373 | if (!ca0132_download_dsp_images(codec)) | ||
4374 | spec->dsp_state = DSP_DOWNLOAD_FAILED; | ||
4375 | else | ||
4376 | spec->dsp_state = DSP_DOWNLOADED; | ||
4377 | } | ||
4378 | |||
4379 | if (spec->dsp_state == DSP_DOWNLOADED) | ||
4380 | ca0132_set_dsp_msr(codec, true); | ||
4381 | } | ||
4382 | |||
4333 | static void ca0132_config(struct hda_codec *codec) | 4383 | static void ca0132_config(struct hda_codec *codec) |
4334 | { | 4384 | { |
4335 | struct ca0132_spec *spec = codec->spec; | 4385 | struct ca0132_spec *spec = codec->spec; |
@@ -4369,6 +4419,47 @@ static void ca0132_config(struct hda_codec *codec) | |||
4369 | cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; | 4419 | cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; |
4370 | } | 4420 | } |
4371 | 4421 | ||
4422 | static void ca0132_process_dsp_response(struct hda_codec *codec) | ||
4423 | { | ||
4424 | struct ca0132_spec *spec = codec->spec; | ||
4425 | |||
4426 | snd_printdd(KERN_INFO "ca0132_process_dsp_response\n"); | ||
4427 | if (spec->wait_scp) { | ||
4428 | if (dspio_get_response_data(codec) >= 0) | ||
4429 | spec->wait_scp = 0; | ||
4430 | } | ||
4431 | |||
4432 | dspio_clear_response_queue(codec); | ||
4433 | } | ||
4434 | |||
4435 | static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res) | ||
4436 | { | ||
4437 | snd_printdd(KERN_INFO "ca0132_unsol_event: 0x%x\n", res); | ||
4438 | |||
4439 | |||
4440 | if (((res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f) == UNSOL_TAG_DSP) { | ||
4441 | ca0132_process_dsp_response(codec); | ||
4442 | } else { | ||
4443 | res = snd_hda_jack_get_action(codec, | ||
4444 | (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f); | ||
4445 | |||
4446 | snd_printdd(KERN_INFO "snd_hda_jack_get_action: 0x%x\n", res); | ||
4447 | |||
4448 | switch (res) { | ||
4449 | case UNSOL_TAG_HP: | ||
4450 | ca0132_select_out(codec); | ||
4451 | snd_hda_jack_report_sync(codec); | ||
4452 | break; | ||
4453 | case UNSOL_TAG_AMIC1: | ||
4454 | ca0132_select_mic(codec); | ||
4455 | snd_hda_jack_report_sync(codec); | ||
4456 | break; | ||
4457 | default: | ||
4458 | break; | ||
4459 | } | ||
4460 | } | ||
4461 | } | ||
4462 | |||
4372 | /* | 4463 | /* |
4373 | * Verbs tables. | 4464 | * Verbs tables. |
4374 | */ | 4465 | */ |
@@ -4483,96 +4574,6 @@ static void ca0132_exit_chip(struct hda_codec *codec) | |||
4483 | dsp_reset(codec); | 4574 | dsp_reset(codec); |
4484 | } | 4575 | } |
4485 | 4576 | ||
4486 | static void ca0132_set_dsp_msr(struct hda_codec *codec, bool is96k) | ||
4487 | { | ||
4488 | chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, is96k); | ||
4489 | chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, is96k); | ||
4490 | chipio_set_control_flag(codec, CONTROL_FLAG_SRC_RATE_96KHZ, is96k); | ||
4491 | chipio_set_control_flag(codec, CONTROL_FLAG_SRC_CLOCK_196MHZ, is96k); | ||
4492 | chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, is96k); | ||
4493 | chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_96KHZ, is96k); | ||
4494 | |||
4495 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000); | ||
4496 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000); | ||
4497 | chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000); | ||
4498 | } | ||
4499 | |||
4500 | static bool ca0132_download_dsp_images(struct hda_codec *codec) | ||
4501 | { | ||
4502 | bool dsp_loaded = false; | ||
4503 | const struct dsp_image_seg *dsp_os_image; | ||
4504 | |||
4505 | if (request_firmware_cached(&fw_efx, EFX_FILE, | ||
4506 | codec->bus->card->dev) != 0) | ||
4507 | return false; | ||
4508 | |||
4509 | dsp_os_image = (struct dsp_image_seg *)(fw_efx->data); | ||
4510 | dspload_image(codec, dsp_os_image, 0, 0, true, 0); | ||
4511 | dsp_loaded = dspload_wait_loaded(codec); | ||
4512 | |||
4513 | return dsp_loaded; | ||
4514 | } | ||
4515 | |||
4516 | static void ca0132_download_dsp(struct hda_codec *codec) | ||
4517 | { | ||
4518 | struct ca0132_spec *spec = codec->spec; | ||
4519 | |||
4520 | spec->dsp_state = DSP_DOWNLOAD_INIT; | ||
4521 | |||
4522 | if (spec->dsp_state == DSP_DOWNLOAD_INIT) { | ||
4523 | chipio_enable_clocks(codec); | ||
4524 | spec->dsp_state = DSP_DOWNLOADING; | ||
4525 | if (!ca0132_download_dsp_images(codec)) | ||
4526 | spec->dsp_state = DSP_DOWNLOAD_FAILED; | ||
4527 | else | ||
4528 | spec->dsp_state = DSP_DOWNLOADED; | ||
4529 | } | ||
4530 | |||
4531 | if (spec->dsp_state == DSP_DOWNLOADED) | ||
4532 | ca0132_set_dsp_msr(codec, true); | ||
4533 | } | ||
4534 | |||
4535 | static void ca0132_process_dsp_response(struct hda_codec *codec) | ||
4536 | { | ||
4537 | struct ca0132_spec *spec = codec->spec; | ||
4538 | |||
4539 | snd_printdd(KERN_INFO "ca0132_process_dsp_response\n"); | ||
4540 | if (spec->wait_scp) { | ||
4541 | if (dspio_get_response_data(codec) >= 0) | ||
4542 | spec->wait_scp = 0; | ||
4543 | } | ||
4544 | |||
4545 | dspio_clear_response_queue(codec); | ||
4546 | } | ||
4547 | |||
4548 | static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res) | ||
4549 | { | ||
4550 | snd_printdd(KERN_INFO "ca0132_unsol_event: 0x%x\n", res); | ||
4551 | |||
4552 | |||
4553 | if (((res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f) == UNSOL_TAG_DSP) { | ||
4554 | ca0132_process_dsp_response(codec); | ||
4555 | } else { | ||
4556 | res = snd_hda_jack_get_action(codec, | ||
4557 | (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f); | ||
4558 | |||
4559 | snd_printdd(KERN_INFO "snd_hda_jack_get_action: 0x%x\n", res); | ||
4560 | |||
4561 | switch (res) { | ||
4562 | case UNSOL_TAG_HP: | ||
4563 | ca0132_select_out(codec); | ||
4564 | snd_hda_jack_report_sync(codec); | ||
4565 | break; | ||
4566 | case UNSOL_TAG_AMIC1: | ||
4567 | ca0132_select_mic(codec); | ||
4568 | snd_hda_jack_report_sync(codec); | ||
4569 | break; | ||
4570 | default: | ||
4571 | break; | ||
4572 | } | ||
4573 | } | ||
4574 | } | ||
4575 | |||
4576 | static int ca0132_init(struct hda_codec *codec) | 4577 | static int ca0132_init(struct hda_codec *codec) |
4577 | { | 4578 | { |
4578 | struct ca0132_spec *spec = codec->spec; | 4579 | struct ca0132_spec *spec = codec->spec; |