From 9db13e5f2d6dc85150cb8a69ab220b84d9b9fbe7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 11:03:48 +0100 Subject: [PATCH 01/54] drm/i915: Enable VLV audio chicken bit for LPE audio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The audio chicken bit (register offset 0x62f38) seems required to make DP audio working on some machines. At least, on Dell Wyse 3040, I failed to get the audio unless this bit is set once. Strangely, the bit seems necessary only once, and it persists after that, even some power-off cycles. The register is supposedly write-only, so it's no evidence whether the bit keeps effect persistently. But, judging from the experiment, it looks enough to set it up once at the device initialization. The patch is basically a cut from the original patch by Pierre-Louis Bossart. v1->v2: drop read since it's a write-only reg. Cc: Pierre-Louis Bossart Reviewed-by: Ville Syrjälä Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_lpe_audio.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4e24ba0cdbe8..4f15a3dc6d98 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2062,6 +2062,9 @@ enum skl_disp_power_wells { #define I915_HDMI_LPE_AUDIO_SIZE 0x1000 /* DisplayPort Audio w/ LPE */ +#define VLV_AUD_CHICKEN_BIT_REG _MMIO(VLV_DISPLAY_BASE + 0x62F38) +#define VLV_CHICKEN_BIT_DBG_ENABLE (1 << 0) + #define _VLV_AUD_PORT_EN_B_DBG (VLV_DISPLAY_BASE + 0x62F20) #define _VLV_AUD_PORT_EN_C_DBG (VLV_DISPLAY_BASE + 0x62F30) #define _VLV_AUD_PORT_EN_D_DBG (VLV_DISPLAY_BASE + 0x62F34) diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index d3ffe0012692..7a5b41b1c024 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -248,6 +248,11 @@ static int lpe_audio_setup(struct drm_i915_private *dev_priv) goto err_free_irq; } + /* enable chicken bit; at least this is required for Dell Wyse 3040 + * with DP outputs (but only sometimes by some reason!) + */ + I915_WRITE(VLV_AUD_CHICKEN_BIT_REG, VLV_CHICKEN_BIT_DBG_ENABLE); + return 0; err_free_irq: irq_free_desc(dev_priv->lpe_audio.irq); From 716733032ab3203498f17f785c2e1d1ca08a51a1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 07:30:20 +0100 Subject: [PATCH 02/54] ALSA: x86: Don't set PCM state to DISCONNECTED Theoretically setting the state to SNDRV_PCM_STATE_DISCONNECTED is correct. But, unfortunately, PA gets confused by this action, and it won't re-probe the device after HDMI/DP is re-plugged. (It reprobes only when the card itself is recreated.) As a workaround, set SNDRV_PCM_STATE_SETUP instead. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio_if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 9ae242d62eb2..30b4b25acb24 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -464,7 +464,7 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__); snd_pcm_stop(intelhaddata->stream_info.had_substream, - SNDRV_PCM_STATE_DISCONNECTED); + SNDRV_PCM_STATE_SETUP); spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); } From 4812dcc437fbe0ddc2319dae7c31254f57d4ae44 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 15:58:15 +0100 Subject: [PATCH 03/54] ALSA: x86: Remove v1 ops and structs The v1 code refers to Medfield/Clovertrail. It's not used at all in the current driver, and probably won't be ever. Let's clean this up, then we can go to the next stage of cleanup tasks. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 206 +------------------------------ sound/x86/intel_hdmi_lpe_audio.h | 29 ----- 2 files changed, 1 insertion(+), 234 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 5ce139c1b21d..1e0bc72a8f63 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -280,23 +280,12 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, return had_read_modify(AUD_CONFIG, data, mask); } -static void snd_intelhad_enable_audio_v1(struct snd_pcm_substream *substream, - u8 enable) -{ - had_read_modify(AUD_CONFIG, enable, BIT(0)); -} - static void snd_intelhad_enable_audio_v2(struct snd_pcm_substream *substream, u8 enable) { had_read_modify_aud_config_v2(substream, enable, BIT(0)); } -static void snd_intelhad_reset_audio_v1(u8 reset) -{ - had_write_register(AUD_HDMI_STATUS, reset); -} - static void snd_intelhad_reset_audio_v2(u8 reset) { had_write_register(AUD_HDMI_STATUS_v2, reset); @@ -320,7 +309,7 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, IEC958_AES0_NONAUDIO)>>1; ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & IEC958_AES3_CON_CLOCK)>>4; - cfg_val.cfg_regx.val_bit = ch_stat0.status_0_regx.lpcm_id; + cfg_val.cfg_regx_v2.val_bit = ch_stat0.status_0_regx.lpcm_id; switch (substream->runtime->rate) { case AUD_SAMPLE_RATE_32: @@ -401,58 +390,6 @@ static int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream, return 0; } -/** - * function to initialize audio - * registers and buffer confgiuration registers - * This function is called in the prepare callback - */ -static int snd_intelhad_prog_audio_ctrl_v1(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata) -{ - union aud_cfg cfg_val = {.cfg_regval = 0}; - union aud_buf_config buf_cfg = {.buf_cfgval = 0}; - u8 channels; - - had_prog_status_reg(substream, intelhaddata); - - buf_cfg.buf_cfg_regx.fifo_width = FIFO_THRESHOLD; - buf_cfg.buf_cfg_regx.aud_delay = 0; - had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval); - - channels = substream->runtime->channels; - - switch (channels) { - case 1: - case 2: - cfg_val.cfg_regx.num_ch = CH_STEREO; - cfg_val.cfg_regx.layout = LAYOUT0; - break; - - case 3: - case 4: - cfg_val.cfg_regx.num_ch = CH_THREE_FOUR; - cfg_val.cfg_regx.layout = LAYOUT1; - break; - - case 5: - case 6: - cfg_val.cfg_regx.num_ch = CH_FIVE_SIX; - cfg_val.cfg_regx.layout = LAYOUT1; - break; - - case 7: - case 8: - cfg_val.cfg_regx.num_ch = CH_SEVEN_EIGHT; - cfg_val.cfg_regx.layout = LAYOUT1; - break; - - } - - cfg_val.cfg_regx.val_bit = 1; - had_write_register(AUD_CONFIG, cfg_val.cfg_regval); - return 0; -} - /* * Compute derived values in channel_allocations[]. */ @@ -659,56 +596,6 @@ static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, return 0; } -/** - * snd_intelhad_prog_dip_v1 - to initialize Data Island Packets registers - * - * @substream:substream for which the prepare function is called - * @intelhaddata:substream private data - * - * This function is called in the prepare callback - */ -static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata) -{ - int i; - union aud_ctrl_st ctrl_state = {.ctrl_val = 0}; - union aud_info_frame2 frame2 = {.fr2_val = 0}; - union aud_info_frame3 frame3 = {.fr3_val = 0}; - u8 checksum = 0; - int channels; - - channels = substream->runtime->channels; - - had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); - - frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1; - - frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation( - intelhaddata, channels); - - /*Calculte the byte wide checksum for all valid DIP words*/ - for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (HDMI_INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0; - for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0; - for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0; - - frame2.fr2_regx.chksum = -(checksum); - - had_write_register(AUD_HDMIW_INFOFR, HDMI_INFO_FRAME_WORD1); - had_write_register(AUD_HDMIW_INFOFR, frame2.fr2_val); - had_write_register(AUD_HDMIW_INFOFR, frame3.fr3_val); - - /* program remaining DIP words with zero */ - for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++) - had_write_register(AUD_HDMIW_INFOFR, 0x0); - - ctrl_state.ctrl_regx.dip_freq = 1; - ctrl_state.ctrl_regx.dip_en_sta = 1; - had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); -} - /** * snd_intelhad_prog_dip_v2 - to initialize Data Island Packets registers * @@ -928,32 +815,6 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) return maud_val; } -/** - * snd_intelhad_prog_cts_v1 - Program HDMI audio CTS value - * - * @aud_samp_freq: sampling frequency of audio data - * @tmds: sampling frequency of the display data - * @n_param: N value, depends on aud_samp_freq - * @intelhaddata:substream private data - * - * Program CTS register based on the audio and display sampling frequency - */ -static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, - u32 link_rate, u32 n_param, - struct snd_intelhad *intelhaddata) -{ - u32 cts_val; - u64 dividend, divisor; - - /* Calculate CTS according to HDMI 1.3a spec*/ - dividend = (u64)tmds * n_param*1000; - divisor = 128 * aud_samp_freq; - cts_val = div64_u64(dividend, divisor); - pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n", - tmds, n_param, cts_val); - had_write_register(AUD_HDMI_CTS, (BIT(20) | cts_val)); -} - /** * snd_intelhad_prog_cts_v2 - Program HDMI audio CTS value * @@ -1026,31 +887,6 @@ static int had_calculate_n_value(u32 aud_samp_freq) return n_val; } -/** - * snd_intelhad_prog_n_v1 - Program HDMI audio N value - * - * @aud_samp_freq: sampling frequency of audio data - * @n_param: N value, depends on aud_samp_freq - * @intelhaddata:substream private data - * - * This function is called in the prepare callback. - * It programs based on the audio and display sampling frequency - */ -static int snd_intelhad_prog_n_v1(u32 aud_samp_freq, u32 *n_param, - struct snd_intelhad *intelhaddata) -{ - s32 n_val; - - n_val = had_calculate_n_value(aud_samp_freq); - - if (n_val < 0) - return n_val; - - had_write_register(AUD_N_ENABLE, (BIT(20) | n_val)); - *n_param = n_val; - return 0; -} - /** * snd_intelhad_prog_n_v2 - Program HDMI audio N value * @@ -1087,35 +923,6 @@ static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param, return 0; } -static void had_clear_underrun_intr_v1(struct snd_intelhad *intelhaddata) -{ - u32 hdmi_status, i = 0; - - /* Handle Underrun interrupt within Audio Unit */ - had_write_register(AUD_CONFIG, 0); - /* Reset buffer pointers */ - had_write_register(AUD_HDMI_STATUS, 1); - had_write_register(AUD_HDMI_STATUS, 0); - /** - * The interrupt status 'sticky' bits might not be cleared by - * setting '1' to that bit once... - */ - do { /* clear bit30, 31 AUD_HDMI_STATUS */ - had_read_register(AUD_HDMI_STATUS, &hdmi_status); - pr_debug("HDMI status =0x%x\n", hdmi_status); - if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { - i++; - hdmi_status &= (AUD_CONFIG_MASK_SRDBG | - AUD_CONFIG_MASK_FUNCRST); - hdmi_status |= ~AUD_CONFIG_MASK_UNDERRUN; - had_write_register(AUD_HDMI_STATUS, hdmi_status); - } else - break; - } while (i < MAX_CNT); - if (i >= MAX_CNT) - pr_err("Unable to clear UNDERRUN bits\n"); -} - static void had_clear_underrun_intr_v2(struct snd_intelhad *intelhaddata) { u32 hdmi_status, i = 0; @@ -1775,16 +1582,6 @@ static struct snd_intel_had_interface had_interface = { .resume = hdmi_audio_resume, }; -static struct had_ops had_ops_v1 = { - .enable_audio = snd_intelhad_enable_audio_v1, - .reset_audio = snd_intelhad_reset_audio_v1, - .prog_n = snd_intelhad_prog_n_v1, - .prog_cts = snd_intelhad_prog_cts_v1, - .audio_ctrl = snd_intelhad_prog_audio_ctrl_v1, - .prog_dip = snd_intelhad_prog_dip_v1, - .handle_underrun = had_clear_underrun_intr_v1, -}; - static struct had_ops had_ops_v2 = { .enable_audio = snd_intelhad_enable_audio_v2, .reset_audio = snd_intelhad_reset_audio_v2, @@ -1934,7 +1731,6 @@ int hdmi_audio_probe(void *deviceptr) } intelhaddata->hw_silence = 1; - had_ops_v1 = had_ops_v1; /* unused */ intelhaddata->ops = &had_ops_v2; return retval; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 3aed89af5b45..5d94aaf0b980 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -358,19 +358,6 @@ struct channel_map_table { * */ union aud_cfg { - struct { - u32 aud_en:1; - u32 layout:1; - u32 fmt:2; - u32 num_ch:2; - u32 rsvd0:1; - u32 set:1; - u32 flat:1; - u32 val_bit:1; - u32 user_bit:1; - u32 underrun:1; - u32 rsvd1:20; - } cfg_regx; struct { u32 aud_en:1; u32 layout:1; @@ -438,11 +425,6 @@ union aud_ch_status_1 { * */ union aud_hdmi_cts { - struct { - u32 cts_val:20; - u32 en_cts_prog:1; - u32 rsvd:11; - } cts_regx; struct { u32 cts_val:24; u32 en_cts_prog:1; @@ -459,11 +441,6 @@ union aud_hdmi_cts { * */ union aud_hdmi_n_enable { - struct { - u32 n_val:20; - u32 en_n_prog:1; - u32 rsvd:11; - } n_regx; struct { u32 n_val:24; u32 en_n_prog:1; @@ -480,12 +457,6 @@ union aud_hdmi_n_enable { * */ union aud_buf_config { - struct { - u32 fifo_width:8; - u32 rsvd0:8; - u32 aud_delay:8; - u32 rsvd1:8; - } buf_cfg_regx; struct { u32 audio_fifo_watermark:8; u32 dma_fifo_watermark:3; From 76296ef0ecec9bb887be22105744e429c6a5422a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 16:09:11 +0100 Subject: [PATCH 04/54] ALSA: x86: Drop indirect calls of had_ops We have only a single implementation of had_ops, hence there is no merit to use the indirect calls at all. Let's replace it with the direct calls -- which allows the compiler more optimizations. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 85 ++++++++++++++------------------- sound/x86/intel_hdmi_audio.h | 21 ++------ sound/x86/intel_hdmi_audio_if.c | 4 +- 3 files changed, 42 insertions(+), 68 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 1e0bc72a8f63..84ce4e09ada5 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -280,13 +280,12 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, return had_read_modify(AUD_CONFIG, data, mask); } -static void snd_intelhad_enable_audio_v2(struct snd_pcm_substream *substream, - u8 enable) +void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable) { had_read_modify_aud_config_v2(substream, enable, BIT(0)); } -static void snd_intelhad_reset_audio_v2(u8 reset) +static void snd_intelhad_reset_audio(u8 reset) { had_write_register(AUD_HDMI_STATUS_v2, reset); } @@ -359,13 +358,13 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, return 0; } -/** +/* * function to initialize audio * registers and buffer confgiuration registers * This function is called in the prepare callback */ -static int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata) +static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) { union aud_cfg cfg_val = {.cfg_regval = 0}; union aud_buf_config buf_cfg = {.buf_cfgval = 0}; @@ -596,16 +595,16 @@ static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, return 0; } -/** - * snd_intelhad_prog_dip_v2 - to initialize Data Island Packets registers +/* + * snd_intelhad_prog_dip - to initialize Data Island Packets registers * * @substream:substream for which the prepare function is called * @intelhaddata:substream private data * * This function is called in the prepare callback */ -static void snd_intelhad_prog_dip_v2(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata) +static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) { int i; union aud_ctrl_st ctrl_state = {.ctrl_val = 0}; @@ -815,8 +814,8 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) return maud_val; } -/** - * snd_intelhad_prog_cts_v2 - Program HDMI audio CTS value +/* + * snd_intelhad_prog_cts - Program HDMI audio CTS value * * @aud_samp_freq: sampling frequency of audio data * @tmds: sampling frequency of the display data @@ -825,9 +824,9 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) * * Program CTS register based on the audio and display sampling frequency */ -static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds, - u32 link_rate, u32 n_param, - struct snd_intelhad *intelhaddata) +static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, + u32 link_rate, u32 n_param, + struct snd_intelhad *intelhaddata) { u32 cts_val; u64 dividend, divisor; @@ -887,8 +886,8 @@ static int had_calculate_n_value(u32 aud_samp_freq) return n_val; } -/** - * snd_intelhad_prog_n_v2 - Program HDMI audio N value +/* + * snd_intelhad_prog_n - Program HDMI audio N value * * @aud_samp_freq: sampling frequency of audio data * @n_param: N value, depends on aud_samp_freq @@ -897,8 +896,8 @@ static int had_calculate_n_value(u32 aud_samp_freq) * This function is called in the prepare callback. * It programs based on the audio and display sampling frequency */ -static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param, - struct snd_intelhad *intelhaddata) +static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, + struct snd_intelhad *intelhaddata) { s32 n_val; @@ -923,7 +922,7 @@ static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param, return 0; } -static void had_clear_underrun_intr_v2(struct snd_intelhad *intelhaddata) +void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) { u32 hdmi_status, i = 0; @@ -1209,7 +1208,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, caps = HDMI_AUDIO_BUFFER_DONE; retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps); retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL); - intelhaddata->ops->enable_audio(substream, 1); + snd_intelhad_enable_audio(substream, 1); pr_debug("Processed _Start\n"); @@ -1232,10 +1231,10 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, */ caps = HDMI_AUDIO_BUFFER_DONE; had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); - intelhaddata->ops->enable_audio(substream, 0); + snd_intelhad_enable_audio(substream, 0); /* Reset buffer pointers */ - intelhaddata->ops->reset_audio(1); - intelhaddata->ops->reset_audio(0); + snd_intelhad_reset_audio(1); + snd_intelhad_reset_audio(0); stream->stream_status = STREAM_DROPPED; had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); break; @@ -1304,8 +1303,8 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) had_get_caps(HAD_GET_ELD, &intelhaddata->eeld); had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); - retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param, - intelhaddata); + retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, + intelhaddata); if (retval) { pr_err("programming N value failed %#x\n", retval); goto prep_end; @@ -1315,13 +1314,13 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) had_get_caps(HAD_GET_LINK_RATE, &link_rate); - intelhaddata->ops->prog_cts(substream->runtime->rate, - disp_samp_freq, link_rate, - n_param, intelhaddata); + snd_intelhad_prog_cts(substream->runtime->rate, + disp_samp_freq, link_rate, + n_param, intelhaddata); - intelhaddata->ops->prog_dip(substream, intelhaddata); + snd_intelhad_prog_dip(substream, intelhaddata); - retval = intelhaddata->ops->audio_ctrl(substream, intelhaddata); + retval = snd_intelhad_audio_ctrl(substream, intelhaddata); /* Prog buffer address */ retval = snd_intelhad_prog_buffer(intelhaddata, @@ -1431,7 +1430,7 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); /* Disable Audio */ - intelhaddata->ops->enable_audio(substream, 0); + snd_intelhad_enable_audio(substream, 0); /* Update CTS value */ retval = had_get_caps(HAD_GET_DISPLAY_RATE, &disp_samp_freq); @@ -1440,8 +1439,8 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) goto out; } - retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param, - intelhaddata); + retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, + intelhaddata); if (retval) { pr_err("programming N value failed %#x\n", retval); goto out; @@ -1450,12 +1449,12 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) if (intelhaddata->dp_output) had_get_caps(HAD_GET_LINK_RATE, &link_rate); - intelhaddata->ops->prog_cts(substream->runtime->rate, - disp_samp_freq, link_rate, - n_param, intelhaddata); + snd_intelhad_prog_cts(substream->runtime->rate, + disp_samp_freq, link_rate, + n_param, intelhaddata); /* Enable Audio */ - intelhaddata->ops->enable_audio(substream, 1); + snd_intelhad_enable_audio(substream, 1); out: return retval; @@ -1582,15 +1581,6 @@ static struct snd_intel_had_interface had_interface = { .resume = hdmi_audio_resume, }; -static struct had_ops had_ops_v2 = { - .enable_audio = snd_intelhad_enable_audio_v2, - .reset_audio = snd_intelhad_reset_audio_v2, - .prog_n = snd_intelhad_prog_n_v2, - .prog_cts = snd_intelhad_prog_cts_v2, - .audio_ctrl = snd_intelhad_prog_audio_ctrl_v2, - .prog_dip = snd_intelhad_prog_dip_v2, - .handle_underrun = had_clear_underrun_intr_v2, -}; /** * hdmi_audio_probe - to create sound card instance for HDMI audio playabck * @@ -1731,7 +1721,6 @@ int hdmi_audio_probe(void *deviceptr) } intelhaddata->hw_silence = 1; - intelhaddata->ops = &had_ops_v2; return retval; err: diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 034b3873ffa1..394959f0bd2e 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -123,7 +123,6 @@ struct had_callback_ops { * @chmap: holds channel map info * @audio_reg_base: hdmi audio register base offset * @hw_silence: flag indicates SoC support for HW silence/Keep alive - * @ops: holds ops functions based on platform */ struct snd_intelhad { struct snd_card *card; @@ -149,25 +148,8 @@ struct snd_intelhad { unsigned int *audio_reg_base; unsigned int audio_cfg_offset; bool hw_silence; - struct had_ops *ops; }; -struct had_ops { - void (*enable_audio)(struct snd_pcm_substream *substream, - u8 enable); - void (*reset_audio)(u8 reset); - int (*prog_n)(u32 aud_samp_freq, u32 *n_param, - struct snd_intelhad *intelhaddata); - void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 link_rate, - u32 n_param, struct snd_intelhad *intelhaddata); - int (*audio_ctrl)(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata); - void (*prog_dip)(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata); - void (*handle_underrun)(struct snd_intelhad *intelhaddata); -}; - - int had_event_handler(enum had_event_type event_type, void *data); int hdmi_audio_query(void *drv_data, struct hdmi_audio_event event); @@ -185,6 +167,9 @@ int snd_intelhad_invd_buffer(int start, int end); int snd_intelhad_read_len(struct snd_intelhad *intelhaddata); void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata); +void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable); +void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata); + /* Register access functions */ int had_get_hwstate(struct snd_intelhad *intelhaddata); int had_get_caps(enum had_caps_list query_element, void *capabilties); diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 30b4b25acb24..d92fe48d916b 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -349,7 +349,7 @@ int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) pr_debug("Enter:%s buf_id=%d, stream_type=%d\n", __func__, buf_id, stream_type); - intelhaddata->ops->handle_underrun(intelhaddata); + snd_intelhad_handle_underrun(intelhaddata); if (drv_status == HAD_DRV_DISCONNECTED) { pr_err("%s:Device already disconnected\n", __func__); @@ -451,7 +451,7 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) caps = HDMI_AUDIO_BUFFER_DONE; retval = had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); retval = had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); - intelhaddata->ops->enable_audio( + snd_intelhad_enable_audio( intelhaddata->stream_info.had_substream, 0); } From f23df8071b178dcfa4f6014baf9323ddaa33e1fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 16:29:39 +0100 Subject: [PATCH 05/54] ALSA: x86: Replace indirect register ops with direct calls Now about the indirect register ops: they are replaced with direct calls, too. The read / write / modify ops are simply replaced with the corresponding functions. The difference is that we calculate the offset inside the function now. So all the had_config_offset references in the caller side are dropped. This also simplifies the DP-audio check in hdmi_audio_write() and hdmi_audio_rmw(). The hdmi_audio_get_register_base is dropped since it's no longer used when the base address and config offset are referred in the read/write functions. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 11 ++-- sound/x86/intel_hdmi_audio.h | 2 - sound/x86/intel_hdmi_audio_if.c | 21 -------- sound/x86/intel_hdmi_lpe_audio.c | 91 ++++++++------------------------ sound/x86/intel_hdmi_lpe_audio.h | 14 ++--- 5 files changed, 30 insertions(+), 109 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 84ce4e09ada5..d101a27e4a27 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -205,8 +205,7 @@ int had_read_register(u32 offset, u32 *data) retval = had_get_hwstate(intelhaddata); if (!retval) - retval = intelhaddata->reg_ops.hdmi_audio_read_register( - offset + intelhaddata->audio_cfg_offset, data); + retval = mid_hdmi_audio_read(offset, data); return retval; } @@ -218,8 +217,7 @@ int had_write_register(u32 offset, u32 data) retval = had_get_hwstate(intelhaddata); if (!retval) - retval = intelhaddata->reg_ops.hdmi_audio_write_register( - offset + intelhaddata->audio_cfg_offset, data); + retval = mid_hdmi_audio_write(offset, data); return retval; } @@ -231,9 +229,7 @@ int had_read_modify(u32 offset, u32 data, u32 mask) retval = had_get_hwstate(intelhaddata); if (!retval) - retval = intelhaddata->reg_ops.hdmi_audio_read_modify( - offset + intelhaddata->audio_cfg_offset, - data, mask); + retval = mid_hdmi_audio_rmw(offset, data, mask); return retval; } @@ -1622,7 +1618,6 @@ int hdmi_audio_probe(void *deviceptr) retval = mid_hdmi_audio_setup( ops_cb.intel_had_event_call_back, - &(intelhaddata->reg_ops), &(intelhaddata->query_ops)); if (retval) { pr_err("querying display driver APIs failed %#x\n", retval); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 394959f0bd2e..5ba06042f669 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -107,7 +107,6 @@ struct had_callback_ops { * @card: ptr to hold card details * @card_index: sound card index * @card_id: detected sound card id - * @reg_ops: register operations to program registers * @query_ops: caps call backs for get/set operations * @drv_status: driver status * @buf_info: ring buffer info @@ -128,7 +127,6 @@ struct snd_intelhad { struct snd_card *card; int card_index; char *card_id; - struct hdmi_audio_registers_ops reg_ops; struct hdmi_audio_query_set_ops query_ops; enum had_drv_status drv_status; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index d92fe48d916b..4334be100655 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -392,22 +392,6 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata) pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id); - /* Query display driver for audio register base */ - if (intelhaddata->reg_ops.hdmi_audio_get_register_base( - &intelhaddata->audio_reg_base, - &intelhaddata->audio_cfg_offset)) { - pr_err("Unable to get audio reg base from Display driver\n"); - goto err; - } - - if (intelhaddata->audio_reg_base == NULL) { - pr_err("audio reg base value is NULL\n"); - goto err; - } - - pr_debug("%s audio_reg_base = 0x%p\n", __func__, - intelhaddata->audio_reg_base); - /* Safety check */ if (substream) { pr_debug("There should not be active PB from ALSA\n"); @@ -420,11 +404,6 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata) had_build_channel_allocation_map(intelhaddata); return 0; - -err: - pm_runtime_disable(intelhaddata->dev); - intelhaddata->dev = NULL; - return 0; } int had_process_hot_unplug(struct snd_intelhad *intelhaddata) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 3cb0f642575c..a7a07bfe52ed 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -178,10 +178,10 @@ void mid_hdmi_audio_signal_event(enum had_event_type event) ctx->had_pvt_data); } -/** +/* * used to write into display controller HDMI audio registers. */ -static int hdmi_audio_write(u32 reg, u32 val) +int mid_hdmi_audio_write(u32 reg, u32 val) { struct hdmi_lpe_audio_ctx *ctx; @@ -190,58 +190,49 @@ static int hdmi_audio_write(u32 reg, u32 val) dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val); if (ctx->dp_output) { - if ((reg == AUDIO_HDMI_CONFIG_A) || - (reg == AUDIO_HDMI_CONFIG_B) || - (reg == AUDIO_HDMI_CONFIG_C)) { - if (val & AUD_CONFIG_VALID_BIT) - val = val | AUD_CONFIG_DP_MODE | - AUD_CONFIG_BLOCK_BIT; - } + if (reg == AUD_CONFIG && (val & AUD_CONFIG_VALID_BIT)) + val |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; } - iowrite32(val, (ctx->mmio_start+reg)); + iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); return 0; } -/** +/* * used to get the register value read from * display controller HDMI audio registers. */ -static int hdmi_audio_read(u32 reg, u32 *val) +int mid_hdmi_audio_read(u32 reg, u32 *val) { struct hdmi_lpe_audio_ctx *ctx; ctx = platform_get_drvdata(hlpe_pdev); - *val = ioread32(ctx->mmio_start+reg); + *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val); return 0; } -/** +/* * used to update the masked bits in display controller HDMI * audio registers. */ -static int hdmi_audio_rmw(u32 reg, u32 val, u32 mask) +int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask) { struct hdmi_lpe_audio_ctx *ctx; u32 val_tmp = 0; ctx = platform_get_drvdata(hlpe_pdev); - val_tmp = (val & mask) | - ((ioread32(ctx->mmio_start + reg)) & ~mask); + val_tmp = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); + val_tmp &= ~mask; + val_tmp |= (val & mask); if (ctx->dp_output) { - if ((reg == AUDIO_HDMI_CONFIG_A) || - (reg == AUDIO_HDMI_CONFIG_B) || - (reg == AUDIO_HDMI_CONFIG_C)) { - if (val_tmp & AUD_CONFIG_VALID_BIT) - val_tmp = val_tmp | AUD_CONFIG_DP_MODE | - AUD_CONFIG_BLOCK_BIT; - } + if (reg == AUD_CONFIG && (val_tmp & AUD_CONFIG_VALID_BIT)) + val_tmp |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; } - iowrite32(val_tmp, (ctx->mmio_start+reg)); + iowrite32(val_tmp, ctx->mmio_start + ctx->had_config_offset + reg); dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val_tmp); @@ -290,22 +281,6 @@ static int hdmi_audio_get_caps(enum had_caps_list get_element, return ret; } -/** - * used to get the current hdmi base address - */ -int hdmi_audio_get_register_base(u32 **reg_base, - u32 *config_offset) -{ - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - *reg_base = (u32 *)(ctx->mmio_start); - *config_offset = ctx->had_config_offset; - dev_dbg(&hlpe_pdev->dev, "%s: reg_base = 0x%p, cfg_off = 0x%x\n", - __func__, *reg_base, *config_offset); - return 0; -} - /** * used to set the HDMI audio capabilities. * e.g. Audio INT. @@ -324,15 +299,11 @@ int hdmi_audio_set_caps(enum had_caps_list set_element, { u32 status_reg; - hdmi_audio_read(AUD_HDMI_STATUS_v2 + - ctx->had_config_offset, &status_reg); + mid_hdmi_audio_read(AUD_HDMI_STATUS_v2, &status_reg); status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; - hdmi_audio_write(AUD_HDMI_STATUS_v2 + - ctx->had_config_offset, status_reg); - hdmi_audio_read(AUD_HDMI_STATUS_v2 + - ctx->had_config_offset, &status_reg); - + mid_hdmi_audio_write(AUD_HDMI_STATUS_v2, status_reg); + mid_hdmi_audio_read(AUD_HDMI_STATUS_v2, &status_reg); } break; default: @@ -342,13 +313,6 @@ int hdmi_audio_set_caps(enum had_caps_list set_element, return 0; } -static struct hdmi_audio_registers_ops hdmi_audio_reg_ops = { - .hdmi_audio_get_register_base = hdmi_audio_get_register_base, - .hdmi_audio_read_register = hdmi_audio_read, - .hdmi_audio_write_register = hdmi_audio_write, - .hdmi_audio_read_modify = hdmi_audio_rmw, -}; - static struct hdmi_audio_query_set_ops hdmi_audio_get_set_ops = { .hdmi_audio_get_caps = hdmi_audio_get_caps, .hdmi_audio_set_caps = hdmi_audio_set_caps, @@ -356,7 +320,6 @@ static struct hdmi_audio_query_set_ops hdmi_audio_get_set_ops = { int mid_hdmi_audio_setup( had_event_call_back audio_callbacks, - struct hdmi_audio_registers_ops *reg_ops, struct hdmi_audio_query_set_ops *query_ops) { struct hdmi_lpe_audio_ctx *ctx; @@ -365,14 +328,6 @@ int mid_hdmi_audio_setup( dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); - reg_ops->hdmi_audio_get_register_base = - (hdmi_audio_reg_ops.hdmi_audio_get_register_base); - reg_ops->hdmi_audio_read_register = - (hdmi_audio_reg_ops.hdmi_audio_read_register); - reg_ops->hdmi_audio_write_register = - (hdmi_audio_reg_ops.hdmi_audio_write_register); - reg_ops->hdmi_audio_read_modify = - (hdmi_audio_reg_ops.hdmi_audio_read_modify); query_ops->hdmi_audio_get_caps = hdmi_audio_get_set_ops.hdmi_audio_get_caps; query_ops->hdmi_audio_set_caps = @@ -421,17 +376,17 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) ctx = platform_get_drvdata(hlpe_pdev); - audio_reg = ctx->had_config_offset + AUD_HDMI_STATUS_v2; - hdmi_audio_read(audio_reg, &audio_stat); + audio_reg = AUD_HDMI_STATUS_v2; + mid_hdmi_audio_read(audio_reg, &audio_stat); if (audio_stat & HDMI_AUDIO_UNDERRUN) { - hdmi_audio_write(audio_reg, HDMI_AUDIO_UNDERRUN); + mid_hdmi_audio_write(audio_reg, HDMI_AUDIO_UNDERRUN); mid_hdmi_audio_signal_event( HAD_EVENT_AUDIO_BUFFER_UNDERRUN); } if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { - hdmi_audio_write(audio_reg, HDMI_AUDIO_BUFFER_DONE); + mid_hdmi_audio_write(audio_reg, HDMI_AUDIO_BUFFER_DONE); mid_hdmi_audio_signal_event( HAD_EVENT_AUDIO_BUFFER_DONE); } diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 5d94aaf0b980..ea90cf919948 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -641,15 +641,6 @@ enum had_event_type { typedef int (*had_event_call_back) (enum had_event_type event_type, void *ctxt_info); -struct hdmi_audio_registers_ops { - int (*hdmi_audio_get_register_base)(u32 **reg_base, - u32 *config_offset); - int (*hdmi_audio_read_register)(u32 reg_addr, u32 *data); - int (*hdmi_audio_write_register)(u32 reg_addr, u32 data); - int (*hdmi_audio_read_modify)(u32 reg_addr, u32 data, - u32 mask); -}; - struct hdmi_audio_query_set_ops { int (*hdmi_audio_get_caps)(enum had_caps_list query_element, void *capabilties); @@ -674,10 +665,13 @@ void mid_hdmi_audio_resume(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); int mid_hdmi_audio_setup( had_event_call_back audio_callbacks, - struct hdmi_audio_registers_ops *reg_ops, struct hdmi_audio_query_set_ops *query_ops); int mid_hdmi_audio_register( struct snd_intel_had_interface *driver, void *had_data); +int mid_hdmi_audio_read(u32 reg, u32 *val); +int mid_hdmi_audio_write(u32 reg, u32 val); +int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask); + #endif From 9eca88c881f1c74c7f5dda3c67cb0b4178429e93 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 16:37:06 +0100 Subject: [PATCH 06/54] ALSA: x86: Replace indirect query_ops with direct calls Like the previous patch, this replaces the indirect query_ops calls via direct function calls. They are only get_caps and set_caps, so fairly straightforward at this time. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 10 +++------- sound/x86/intel_hdmi_audio.h | 2 -- sound/x86/intel_hdmi_lpe_audio.c | 26 +++++++------------------- sound/x86/intel_hdmi_lpe_audio.h | 16 ++++++---------- 4 files changed, 16 insertions(+), 38 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index d101a27e4a27..a4c2f3f8d669 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -179,8 +179,7 @@ int had_get_caps(enum had_caps_list query, void *caps) retval = had_get_hwstate(intelhaddata); if (!retval) - retval = intelhaddata->query_ops.hdmi_audio_get_caps(query, - caps); + retval = mid_hdmi_audio_get_caps(query, caps); return retval; } @@ -192,8 +191,7 @@ int had_set_caps(enum had_caps_list set_element, void *caps) retval = had_get_hwstate(intelhaddata); if (!retval) - retval = intelhaddata->query_ops.hdmi_audio_set_caps( - set_element, caps); + retval = mid_hdmi_audio_set_caps(set_element, caps); return retval; } @@ -1616,9 +1614,7 @@ int hdmi_audio_probe(void *deviceptr) /* registering with display driver to get access to display APIs */ - retval = mid_hdmi_audio_setup( - ops_cb.intel_had_event_call_back, - &(intelhaddata->query_ops)); + retval = mid_hdmi_audio_setup(ops_cb.intel_had_event_call_back); if (retval) { pr_err("querying display driver APIs failed %#x\n", retval); goto free_hadstream; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 5ba06042f669..e7c7432c5078 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -107,7 +107,6 @@ struct had_callback_ops { * @card: ptr to hold card details * @card_index: sound card index * @card_id: detected sound card id - * @query_ops: caps call backs for get/set operations * @drv_status: driver status * @buf_info: ring buffer info * @stream_info: stream information @@ -127,7 +126,6 @@ struct snd_intelhad { struct snd_card *card; int card_index; char *card_id; - struct hdmi_audio_query_set_ops query_ops; enum had_drv_status drv_status; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index a7a07bfe52ed..1747ff259903 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -239,12 +239,12 @@ int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask) return 0; } -/** +/* * used to return the HDMI audio capabilities. * e.g. resolution, frame rate. */ -static int hdmi_audio_get_caps(enum had_caps_list get_element, - void *capabilities) +int mid_hdmi_audio_get_caps(enum had_caps_list get_element, + void *capabilities) { struct hdmi_lpe_audio_ctx *ctx; int ret = 0; @@ -281,12 +281,12 @@ static int hdmi_audio_get_caps(enum had_caps_list get_element, return ret; } -/** +/* * used to set the HDMI audio capabilities. * e.g. Audio INT. */ -int hdmi_audio_set_caps(enum had_caps_list set_element, - void *capabilties) +int mid_hdmi_audio_set_caps(enum had_caps_list set_element, + void *capabilties) { struct hdmi_lpe_audio_ctx *ctx; @@ -313,14 +313,7 @@ int hdmi_audio_set_caps(enum had_caps_list set_element, return 0; } -static struct hdmi_audio_query_set_ops hdmi_audio_get_set_ops = { - .hdmi_audio_get_caps = hdmi_audio_get_caps, - .hdmi_audio_set_caps = hdmi_audio_set_caps, -}; - -int mid_hdmi_audio_setup( - had_event_call_back audio_callbacks, - struct hdmi_audio_query_set_ops *query_ops) +int mid_hdmi_audio_setup(had_event_call_back audio_callbacks) { struct hdmi_lpe_audio_ctx *ctx; @@ -328,11 +321,6 @@ int mid_hdmi_audio_setup( dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); - query_ops->hdmi_audio_get_caps = - hdmi_audio_get_set_ops.hdmi_audio_get_caps; - query_ops->hdmi_audio_set_caps = - hdmi_audio_get_set_ops.hdmi_audio_set_caps; - ctx->had_event_callbacks = audio_callbacks; return 0; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index ea90cf919948..5e925b728302 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -641,13 +641,6 @@ enum had_event_type { typedef int (*had_event_call_back) (enum had_event_type event_type, void *ctxt_info); -struct hdmi_audio_query_set_ops { - int (*hdmi_audio_get_caps)(enum had_caps_list query_element, - void *capabilties); - int (*hdmi_audio_set_caps)(enum had_caps_list set_element, - void *capabilties); -}; - struct hdmi_audio_event { int type; }; @@ -663,9 +656,7 @@ bool mid_hdmi_audio_is_busy(void *dev); bool mid_hdmi_audio_suspend(void *dev); void mid_hdmi_audio_resume(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); -int mid_hdmi_audio_setup( - had_event_call_back audio_callbacks, - struct hdmi_audio_query_set_ops *query_ops); +int mid_hdmi_audio_setup(had_event_call_back audio_callbacks); int mid_hdmi_audio_register( struct snd_intel_had_interface *driver, void *had_data); @@ -674,4 +665,9 @@ int mid_hdmi_audio_read(u32 reg, u32 *val); int mid_hdmi_audio_write(u32 reg, u32 val); int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask); +int mid_hdmi_audio_get_caps(enum had_caps_list get_element, + void *capabilities); +int mid_hdmi_audio_set_caps(enum had_caps_list set_element, + void *capabilties); + #endif From 6f9ecc76f4e04b111160d789f36a8c5bf1cc9ab6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 16:52:06 +0100 Subject: [PATCH 07/54] ALSA: x86: Drop snd_intel_had_interface indirect calls Yet another indirection is killed: at this time, it's snd_intel_had_interface. It contains also the name string, but it's nowhere used, thus we can kill it, too. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 9 +--- sound/x86/intel_hdmi_audio.h | 2 +- sound/x86/intel_hdmi_audio_if.c | 3 +- sound/x86/intel_hdmi_lpe_audio.c | 87 +++++++------------------------- sound/x86/intel_hdmi_lpe_audio.h | 13 +---- 5 files changed, 23 insertions(+), 91 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index a4c2f3f8d669..bff46061e5c5 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1568,13 +1568,6 @@ static struct snd_kcontrol_new had_control_iec958 = { .put = had_iec958_put }; -static struct snd_intel_had_interface had_interface = { - .name = "hdmi-audio", - .query = hdmi_audio_query, - .suspend = hdmi_audio_suspend, - .resume = hdmi_audio_resume, -}; - /** * hdmi_audio_probe - to create sound card instance for HDMI audio playabck * @@ -1704,7 +1697,7 @@ int hdmi_audio_probe(void *deviceptr) pm_runtime_enable(intelhaddata->dev); mutex_unlock(&had_mutex); - retval = mid_hdmi_audio_register(&had_interface, intelhaddata); + retval = mid_hdmi_audio_register(intelhaddata); if (retval) { pr_err("registering with display driver failed %#x\n", retval); snd_card_free(card); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index e7c7432c5078..ba13ae63bea3 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -149,7 +149,7 @@ struct snd_intelhad { int had_event_handler(enum had_event_type event_type, void *data); int hdmi_audio_query(void *drv_data, struct hdmi_audio_event event); -int hdmi_audio_suspend(void *drv_data, struct hdmi_audio_event event); +int hdmi_audio_suspend(void *drv_data); int hdmi_audio_resume(void *drv_data); int hdmi_audio_mode_change(struct snd_pcm_substream *substream); extern struct snd_pcm_ops snd_intelhad_playback_ops; diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 4334be100655..88ebcb5f7388 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -91,12 +91,11 @@ int hdmi_audio_query(void *haddata, struct hdmi_audio_event event) * hdmi_audio_suspend - power management suspend function * *@haddata: pointer to HAD private data - *@event: pm event for which this method is invoked * * This function is called by client driver to suspend the * hdmi audio. */ -int hdmi_audio_suspend(void *haddata, struct hdmi_audio_event event) +int hdmi_audio_suspend(void *haddata) { int caps, retval = 0; struct had_pvt_data *had_stream; diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 1747ff259903..51ba3493ff30 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -45,7 +45,6 @@ struct hdmi_lpe_audio_ctx { int irq; void __iomem *mmio_start; had_event_call_back had_event_callbacks; - struct snd_intel_had_interface *had_interface; void *had_pvt_data; int tmds_clock_speed; bool dp_output; @@ -103,63 +102,9 @@ bool mid_hdmi_audio_is_busy(void *ddev) return false; } - if (ctx->had_interface) { - hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; - hdmi_audio_busy = ctx->had_interface->query( - ctx->had_pvt_data, - hdmi_audio_event); - return hdmi_audio_busy != 0; - } - return false; -} - -/* - * return true if HDMI audio device is suspended/ disconnected - */ -bool mid_hdmi_audio_suspend(void *ddev) -{ - struct hdmi_lpe_audio_ctx *ctx; - struct hdmi_audio_event hdmi_audio_event; - int ret = 0; - - ctx = platform_get_drvdata(hlpe_pdev); - - if (hlpe_state == hdmi_connector_status_disconnected) { - /* HDMI is not connected, assuming audio device - * is suspended already. - */ - return true; - } - - dev_dbg(&hlpe_pdev->dev, "%s: hlpe_state %d", __func__, - hlpe_state); - - if (ctx->had_interface) { - hdmi_audio_event.type = 0; - ret = ctx->had_interface->suspend(ctx->had_pvt_data, - hdmi_audio_event); - return (ret == 0) ? true : false; - } - return true; -} - -void mid_hdmi_audio_resume(void *ddev) -{ - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - - if (hlpe_state == hdmi_connector_status_disconnected) { - /* HDMI is not connected, there is no need - * to resume audio device. - */ - return; - } - - dev_dbg(&hlpe_pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); - - if (ctx->had_interface) - ctx->had_interface->resume(ctx->had_pvt_data); + hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; + hdmi_audio_busy = hdmi_audio_query(ctx->had_pvt_data, hdmi_audio_event); + return hdmi_audio_busy != 0; } void mid_hdmi_audio_signal_event(enum had_event_type event) @@ -331,8 +276,7 @@ static void _had_wq(struct work_struct *work) mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); } -int mid_hdmi_audio_register(struct snd_intel_had_interface *driver, - void *had_data) +int mid_hdmi_audio_register(void *had_data) { struct hdmi_lpe_audio_ctx *ctx; @@ -341,7 +285,6 @@ int mid_hdmi_audio_register(struct snd_intel_had_interface *driver, dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); ctx->had_pvt_data = had_data; - ctx->had_interface = driver; /* The Audio driver is loading now and we need to notify * it if there is an HDMI device attached @@ -578,18 +521,26 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) return 0; } -static int hdmi_lpe_audio_suspend(struct platform_device *pt_dev, - pm_message_t state) +static int hdmi_lpe_audio_suspend(struct platform_device *pdev, + pm_message_t state) { - dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); - mid_hdmi_audio_suspend(NULL); + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); + /* HDMI is not connected, assuming audio device is suspended already */ + if (hlpe_state != hdmi_connector_status_disconnected) + hdmi_audio_suspend(ctx->had_pvt_data); return 0; } -static int hdmi_lpe_audio_resume(struct platform_device *pt_dev) +static int hdmi_lpe_audio_resume(struct platform_device *pdev) { - dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); - mid_hdmi_audio_resume(NULL); + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); + /* HDMI is not connected, there is no need to resume audio device */ + if (hlpe_state != hdmi_connector_status_disconnected) + hdmi_audio_resume(ctx->had_pvt_data); return 0; } diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 5e925b728302..518d897f1806 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -645,21 +645,10 @@ struct hdmi_audio_event { int type; }; -struct snd_intel_had_interface { - const char *name; - int (*query)(void *had_data, struct hdmi_audio_event event); - int (*suspend)(void *had_data, struct hdmi_audio_event event); - int (*resume)(void *had_data); -}; - bool mid_hdmi_audio_is_busy(void *dev); -bool mid_hdmi_audio_suspend(void *dev); -void mid_hdmi_audio_resume(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); int mid_hdmi_audio_setup(had_event_call_back audio_callbacks); -int mid_hdmi_audio_register( - struct snd_intel_had_interface *driver, - void *had_data); +int mid_hdmi_audio_register(void *had_data); int mid_hdmi_audio_read(u32 reg, u32 *val); int mid_hdmi_audio_write(u32 reg, u32 val); From 79dda75a2cfc5628f25338122d24ee8789b367cf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:23:39 +0100 Subject: [PATCH 08/54] ALSA: x86: Pass snd_intelhad object to helpers For reducing the global variable reference, keep snd_intelhad object in the context and pass it to each helper. It's a preliminary change for further cleanup. This also includes the simplification of the probe procedure: the LPE platform driver directly gets the created snd_intelhad object by hdmi_audio_probe(), and passes it to each helper and destructor, hdmi_audio_remove(). The hdmi_audio_probe() function doesn't call the back-registration any longer, which is fairly useless. The LPE platform driver initializes the stuff instead at the right place, and calls the wq after the object creation in the probe function itself. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 143 ++++++++++++++++--------------- sound/x86/intel_hdmi_audio.h | 22 +++-- sound/x86/intel_hdmi_audio_if.c | 42 +++++---- sound/x86/intel_hdmi_lpe_audio.c | 49 ++++------- sound/x86/intel_hdmi_lpe_audio.h | 1 - 5 files changed, 129 insertions(+), 128 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index bff46061e5c5..45ba16e27323 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -42,7 +42,6 @@ static DEFINE_MUTEX(had_mutex); /*standard module options for ALSA. This module supports only one card*/ static int hdmi_card_index = SNDRV_DEFAULT_IDX1; static char *hdmi_card_id = SNDRV_DEFAULT_STR1; -static struct snd_intelhad *had_data; static int underrun_count; module_param_named(index, hdmi_card_index, int, 0444); @@ -172,10 +171,10 @@ int had_get_hwstate(struct snd_intelhad *intelhaddata) return 0; } -int had_get_caps(enum had_caps_list query, void *caps) +int had_get_caps(struct snd_intelhad *intelhaddata, + enum had_caps_list query, void *caps) { int retval; - struct snd_intelhad *intelhaddata = had_data; retval = had_get_hwstate(intelhaddata); if (!retval) @@ -184,10 +183,10 @@ int had_get_caps(enum had_caps_list query, void *caps) return retval; } -int had_set_caps(enum had_caps_list set_element, void *caps) +int had_set_caps(struct snd_intelhad *intelhaddata, + enum had_caps_list set_element, void *caps) { int retval; - struct snd_intelhad *intelhaddata = had_data; retval = had_get_hwstate(intelhaddata); if (!retval) @@ -196,10 +195,9 @@ int had_set_caps(enum had_caps_list set_element, void *caps) return retval; } -int had_read_register(u32 offset, u32 *data) +int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) { int retval; - struct snd_intelhad *intelhaddata = had_data; retval = had_get_hwstate(intelhaddata); if (!retval) @@ -208,10 +206,9 @@ int had_read_register(u32 offset, u32 *data) return retval; } -int had_write_register(u32 offset, u32 data) +int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) { int retval; - struct snd_intelhad *intelhaddata = had_data; retval = had_get_hwstate(intelhaddata); if (!retval) @@ -220,10 +217,10 @@ int had_write_register(u32 offset, u32 data) return retval; } -int had_read_modify(u32 offset, u32 data, u32 mask) +int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, + u32 data, u32 mask) { int retval; - struct snd_intelhad *intelhaddata = had_data; retval = had_get_hwstate(intelhaddata); if (!retval) @@ -253,6 +250,7 @@ int had_read_modify(u32 offset, u32 data, u32 mask) static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, u32 data, u32 mask) { + struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); union aud_cfg cfg_val = {.cfg_regval = 0}; u8 channels; @@ -271,7 +269,7 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, pr_debug("%s : data = %x, mask =%x\n", __func__, data, mask); - return had_read_modify(AUD_CONFIG, data, mask); + return had_read_modify(intelhaddata, AUD_CONFIG, data, mask); } void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable) @@ -279,9 +277,10 @@ void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable) had_read_modify_aud_config_v2(substream, enable, BIT(0)); } -static void snd_intelhad_reset_audio(u8 reset) +static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, + u8 reset) { - had_write_register(AUD_HDMI_STATUS_v2, reset); + had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, reset); } /** @@ -334,7 +333,8 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, break; } - had_write_register(AUD_CH_STATUS_0, ch_stat0.status_0_regval); + had_write_register(intelhaddata, + AUD_CH_STATUS_0, ch_stat0.status_0_regval); format = substream->runtime->format; @@ -348,7 +348,8 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, ch_stat1.status_1_regx.max_wrd_len = 0; ch_stat1.status_1_regx.wrd_len = 0; } - had_write_register(AUD_CH_STATUS_1, ch_stat1.status_1_regval); + had_write_register(intelhaddata, + AUD_CH_STATUS_1, ch_stat1.status_1_regval); return 0; } @@ -369,7 +370,7 @@ static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, buf_cfg.buf_cfg_regx_v2.audio_fifo_watermark = FIFO_THRESHOLD; buf_cfg.buf_cfg_regx_v2.dma_fifo_watermark = DMA_FIFO_THRESHOLD; buf_cfg.buf_cfg_regx_v2.aud_delay = 0; - had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval); + had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.buf_cfgval); channels = substream->runtime->channels; cfg_val.cfg_regx_v2.num_ch = channels - 2; @@ -379,7 +380,7 @@ static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, cfg_val.cfg_regx_v2.layout = LAYOUT1; cfg_val.cfg_regx_v2.val_bit = 1; - had_write_register(AUD_CONFIG, cfg_val.cfg_regval); + had_write_register(intelhaddata, AUD_CONFIG, cfg_val.cfg_regval); return 0; } @@ -479,8 +480,8 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) return; } - had_get_caps(HAD_GET_ELD, &intelhaddata->eeld); - had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); + had_get_caps(intelhaddata, HAD_GET_ELD, &intelhaddata->eeld); + had_get_caps(intelhaddata, HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); pr_debug("eeld.speaker_allocation_block = %x\n", intelhaddata->eeld.speaker_allocation_block); @@ -610,7 +611,7 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, channels = substream->runtime->channels; - had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); + had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.ctrl_val); if (intelhaddata->dp_output) { info_frame = DP_INFO_FRAME_WORD1; @@ -633,17 +634,17 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, frame2.fr2_regx.chksum = -(checksum); } - had_write_register(AUD_HDMIW_INFOFR_v2, info_frame); - had_write_register(AUD_HDMIW_INFOFR_v2, frame2.fr2_val); - had_write_register(AUD_HDMIW_INFOFR_v2, frame3.fr3_val); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, info_frame); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, frame2.fr2_val); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, frame3.fr3_val); /* program remaining DIP words with zero */ for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++) - had_write_register(AUD_HDMIW_INFOFR_v2, 0x0); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, 0x0); ctrl_state.ctrl_regx.dip_freq = 1; ctrl_state.ctrl_regx.dip_en_sta = 1; - had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); + had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.ctrl_val); } /** @@ -696,10 +697,12 @@ int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, intelhaddata->buf_info[i].buf_size = ring_buf_size - (period_bytes*i); - had_write_register(AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH), + had_write_register(intelhaddata, + AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH), intelhaddata->buf_info[i].buf_addr | BIT(0) | BIT(1)); - had_write_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), + had_write_register(intelhaddata, + AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), period_bytes); intelhaddata->buf_info[i].is_valid = true; } @@ -716,8 +719,9 @@ int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) u32 len[4]; for (i = 0; i < 4 ; i++) { - had_read_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), - &len[i]); + had_read_register(intelhaddata, + AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), + &len[i]); if (!len[i]) retval++; } @@ -836,7 +840,7 @@ static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, } pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n", tmds, n_param, cts_val); - had_write_register(AUD_HDMI_CTS, (BIT(24) | cts_val)); + had_write_register(intelhaddata, AUD_HDMI_CTS, (BIT(24) | cts_val)); } static int had_calculate_n_value(u32 aud_samp_freq) @@ -911,7 +915,7 @@ static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, if (n_val < 0) return n_val; - had_write_register(AUD_N_ENABLE, (BIT(24) | n_val)); + had_write_register(intelhaddata, AUD_N_ENABLE, (BIT(24) | n_val)); *n_param = n_val; return 0; } @@ -921,20 +925,22 @@ void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) u32 hdmi_status, i = 0; /* Handle Underrun interrupt within Audio Unit */ - had_write_register(AUD_CONFIG, 0); + had_write_register(intelhaddata, AUD_CONFIG, 0); /* Reset buffer pointers */ - had_write_register(AUD_HDMI_STATUS_v2, 1); - had_write_register(AUD_HDMI_STATUS_v2, 0); + had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 1); + had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 0); /** * The interrupt status 'sticky' bits might not be cleared by * setting '1' to that bit once... */ do { /* clear bit30, 31 AUD_HDMI_STATUS */ - had_read_register(AUD_HDMI_STATUS_v2, &hdmi_status); + had_read_register(intelhaddata, AUD_HDMI_STATUS_v2, + &hdmi_status); pr_debug("HDMI status =0x%x\n", hdmi_status); if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { i++; - had_write_register(AUD_HDMI_STATUS_v2, hdmi_status); + had_write_register(intelhaddata, + AUD_HDMI_STATUS_v2, hdmi_status); } else break; } while (i < MAX_CNT); @@ -1200,8 +1206,9 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; */ caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps); - retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL); + retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO_INT, + &caps); + retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO, NULL); snd_intelhad_enable_audio(substream, 1); pr_debug("Processed _Start\n"); @@ -1224,13 +1231,13 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; */ caps = HDMI_AUDIO_BUFFER_DONE; - had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); snd_intelhad_enable_audio(substream, 0); /* Reset buffer pointers */ - snd_intelhad_reset_audio(1); - snd_intelhad_reset_audio(0); + snd_intelhad_reset_audio(intelhaddata, 1); + snd_intelhad_reset_audio(intelhaddata, 0); stream->stream_status = STREAM_DROPPED; - had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); break; default: @@ -1288,14 +1295,15 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) /* Get N value in KHz */ - retval = had_get_caps(HAD_GET_DISPLAY_RATE, &disp_samp_freq); + retval = had_get_caps(intelhaddata, HAD_GET_DISPLAY_RATE, + &disp_samp_freq); if (retval) { pr_err("querying display sampling freq failed %#x\n", retval); goto prep_end; } - had_get_caps(HAD_GET_ELD, &intelhaddata->eeld); - had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); + had_get_caps(intelhaddata, HAD_GET_ELD, &intelhaddata->eeld); + had_get_caps(intelhaddata, HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, intelhaddata); @@ -1305,7 +1313,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) } if (intelhaddata->dp_output) - had_get_caps(HAD_GET_LINK_RATE, &link_rate); + had_get_caps(intelhaddata, HAD_GET_LINK_RATE, &link_rate); snd_intelhad_prog_cts(substream->runtime->rate, @@ -1325,7 +1333,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) * FL, FR, C, LFE, RL, RR */ - had_write_register(AUD_BUF_CH_SWAP, SWAP_LFE_CENTER); + had_write_register(intelhaddata, AUD_BUF_CH_SWAP, SWAP_LFE_CENTER); prep_end: return retval; @@ -1361,7 +1369,8 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( */ buf_id = intelhaddata->curr_buf % 4; - had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t); + had_read_register(intelhaddata, + AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t); if ((t == 0) || (t == ((u32)-1L))) { underrun_count++; @@ -1427,7 +1436,8 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) snd_intelhad_enable_audio(substream, 0); /* Update CTS value */ - retval = had_get_caps(HAD_GET_DISPLAY_RATE, &disp_samp_freq); + retval = had_get_caps(intelhaddata, HAD_GET_DISPLAY_RATE, + &disp_samp_freq); if (retval) { pr_err("querying display sampling freq failed %#x\n", retval); goto out; @@ -1441,7 +1451,7 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) } if (intelhaddata->dp_output) - had_get_caps(HAD_GET_LINK_RATE, &link_rate); + had_get_caps(intelhaddata, HAD_GET_LINK_RATE, &link_rate); snd_intelhad_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate, @@ -1568,16 +1578,17 @@ static struct snd_kcontrol_new had_control_iec958 = { .put = had_iec958_put }; -/** +/* * hdmi_audio_probe - to create sound card instance for HDMI audio playabck * - *@haddata: pointer to HAD private data - *@card_id: card for which probe is called + * @devptr: platform device + * @had_ret: pointer to store the created snd_intelhad object * - * This function is called when the hdmi cable is plugged in. This function + * This function is called when the platform device is probed. This function * creates and registers the sound card with ALSA */ -int hdmi_audio_probe(void *deviceptr) +int hdmi_audio_probe(struct platform_device *devptr, + struct snd_intelhad **had_ret) { int retval; struct snd_pcm *pcm; @@ -1585,7 +1596,6 @@ int hdmi_audio_probe(void *deviceptr) struct had_callback_ops ops_cb; struct snd_intelhad *intelhaddata; struct had_pvt_data *had_stream; - struct platform_device *devptr = deviceptr; pr_debug("Enter %s\n", __func__); @@ -1602,7 +1612,6 @@ int hdmi_audio_probe(void *deviceptr) goto free_haddata; } - had_data = intelhaddata; ops_cb.intel_had_event_call_back = had_event_handler; /* registering with display driver to get access to display APIs */ @@ -1697,16 +1706,11 @@ int hdmi_audio_probe(void *deviceptr) pm_runtime_enable(intelhaddata->dev); mutex_unlock(&had_mutex); - retval = mid_hdmi_audio_register(intelhaddata); - if (retval) { - pr_err("registering with display driver failed %#x\n", retval); - snd_card_free(card); - goto free_hadstream; - } intelhaddata->hw_silence = 1; + *had_ret = intelhaddata; - return retval; + return 0; err: snd_card_free(card); unlock_mutex: @@ -1722,7 +1726,7 @@ free_haddata: return retval; } -/** +/* * hdmi_audio_remove - removes the alsa card * *@haddata: pointer to HAD private data @@ -1730,9 +1734,8 @@ free_haddata: * This function is called when the hdmi cable is un-plugged. This function * free the sound card. */ -int hdmi_audio_remove(void *pdevptr) +int hdmi_audio_remove(struct snd_intelhad *intelhaddata) { - struct snd_intelhad *intelhaddata = had_data; int caps; pr_debug("Enter %s\n", __func__); @@ -1742,8 +1745,8 @@ int hdmi_audio_remove(void *pdevptr) if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); - had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); } snd_card_free(intelhaddata->card); kfree(intelhaddata->private_data); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index ba13ae63bea3..5a82a3f429d7 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -39,6 +39,8 @@ #include #include "intel_hdmi_lpe_audio.h" +struct platform_device; + #define PCM_INDEX 0 #define MAX_PB_STREAMS 1 #define MAX_CAP_STREAMS 0 @@ -168,13 +170,19 @@ void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata); /* Register access functions */ int had_get_hwstate(struct snd_intelhad *intelhaddata); -int had_get_caps(enum had_caps_list query_element, void *capabilties); -int had_set_caps(enum had_caps_list set_element, void *capabilties); -int had_read_register(u32 reg_addr, u32 *data); -int had_write_register(u32 reg_addr, u32 data); -int had_read_modify(u32 reg_addr, u32 data, u32 mask); +int had_get_caps(struct snd_intelhad *intelhaddata, + enum had_caps_list query_element, void *capabilties); +int had_set_caps(struct snd_intelhad *intelhaddata, + enum had_caps_list set_element, void *capabilties); +int had_read_register(struct snd_intelhad *intelhaddata, + u32 reg_addr, u32 *data); +int had_write_register(struct snd_intelhad *intelhaddata, + u32 reg_addr, u32 data); +int had_read_modify(struct snd_intelhad *intelhaddata, + u32 reg_addr, u32 data, u32 mask); -int hdmi_audio_probe(void *devptr); -int hdmi_audio_remove(void *pdev); +int hdmi_audio_probe(struct platform_device *devptr, + struct snd_intelhad **had_ret); +int hdmi_audio_remove(struct snd_intelhad *intelhaddata); #endif /* _INTEL_HDMI_AUDIO_ */ diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 88ebcb5f7388..8e3a0943332b 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -137,8 +137,8 @@ int hdmi_audio_suspend(void *haddata) * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; */ caps = HDMI_AUDIO_BUFFER_DONE; - had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); - had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); pr_debug("Exit:%s", __func__); return retval; } @@ -187,8 +187,8 @@ int hdmi_audio_resume(void *haddata) * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; */ caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps); - retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL); + retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO_INT, &caps); + retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO, NULL); pr_debug("Exit:%s", __func__); return retval; } @@ -221,11 +221,12 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, buf_size = intelhaddata->buf_info[j].buf_size; buf_addr = intelhaddata->buf_info[j].buf_addr; - had_write_register(AUD_BUF_A_LENGTH + - (j * HAD_REG_WIDTH), buf_size); - had_write_register( - AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH), - (buf_addr | BIT(0) | BIT(1))); + had_write_register(intelhaddata, + AUD_BUF_A_LENGTH + + (j * HAD_REG_WIDTH), buf_size); + had_write_register(intelhaddata, + AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH), + (buf_addr | BIT(0) | BIT(1))); } buf_id = buf_id % 4; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); @@ -300,14 +301,17 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata) } /*Reprogram the registers with addr and length*/ - had_write_register(AUD_BUF_A_LENGTH + - (buf_id * HAD_REG_WIDTH), buf_size); - had_write_register(AUD_BUF_A_ADDR+(buf_id * HAD_REG_WIDTH), - intelhaddata->buf_info[buf_id].buf_addr| - BIT(0) | BIT(1)); + had_write_register(intelhaddata, + AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), + buf_size); + had_write_register(intelhaddata, + AUD_BUF_A_ADDR + (buf_id * HAD_REG_WIDTH), + intelhaddata->buf_info[buf_id].buf_addr | + BIT(0) | BIT(1)); - had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), - &len); + had_read_register(intelhaddata, + AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), + &len); pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id); /* In case of actual data, @@ -427,8 +431,10 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) } else { /* Disable Audio */ caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); - retval = had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + retval = had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, + &caps); + retval = had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, + NULL); snd_intelhad_enable_audio( intelhaddata->stream_info.had_substream, 0); } diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 51ba3493ff30..18a2ae6796b8 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -45,7 +45,7 @@ struct hdmi_lpe_audio_ctx { int irq; void __iomem *mmio_start; had_event_call_back had_event_callbacks; - void *had_pvt_data; + struct snd_intelhad *had; int tmds_clock_speed; bool dp_output; int link_rate; @@ -103,7 +103,7 @@ bool mid_hdmi_audio_is_busy(void *ddev) } hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; - hdmi_audio_busy = hdmi_audio_query(ctx->had_pvt_data, hdmi_audio_event); + hdmi_audio_busy = hdmi_audio_query(ctx->had, hdmi_audio_event); return hdmi_audio_busy != 0; } @@ -119,8 +119,7 @@ void mid_hdmi_audio_signal_event(enum had_event_type event) * event handlers to avoid races */ if (ctx->had_event_callbacks) - (*ctx->had_event_callbacks)(event, - ctx->had_pvt_data); + (*ctx->had_event_callbacks)(event, ctx->had); } /* @@ -276,27 +275,6 @@ static void _had_wq(struct work_struct *work) mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); } -int mid_hdmi_audio_register(void *had_data) -{ - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - - dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); - - ctx->had_pvt_data = had_data; - - /* The Audio driver is loading now and we need to notify - * it if there is an HDMI device attached - */ - INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); - dev_dbg(&hlpe_pdev->dev, "%s: Scheduling HDMI audio work queue\n", - __func__); - schedule_work(&ctx->hdmi_audio_wq); - - return 0; -} - static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { u32 audio_stat, audio_reg; @@ -460,6 +438,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: irq num = %d\n", irq); ctx->mmio_start = mmio_start; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; + INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); if (pci_dev_present(cherryview_ids)) dev_dbg(&hlpe_pdev->dev, "%s: Cherrytrail LPE - Detected\n", @@ -483,9 +462,16 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - ret = hdmi_audio_probe((void *)pdev); + ret = hdmi_audio_probe(pdev, &ctx->had); dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); + /* The Audio driver is loading now and we need to notify + * it if there is an HDMI device attached + */ + dev_dbg(&hlpe_pdev->dev, "%s: Scheduling HDMI audio work queue\n", + __func__); + schedule_work(&ctx->hdmi_audio_wq); + spin_lock_irqsave(&pdata->lpe_audio_slock, flag_irq); pdata->notify_audio_lpe = notify_audio_lpe; if (pdata->notify_pending) { @@ -507,14 +493,13 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) */ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { - struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); - hdmi_audio_remove(pdev); + hdmi_audio_remove(ctx->had); - /* get context, release resources */ - ctx = platform_get_drvdata(pdev); + /* release resources */ iounmap(ctx->mmio_start); free_irq(ctx->irq, NULL); kfree(ctx); @@ -529,7 +514,7 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); /* HDMI is not connected, assuming audio device is suspended already */ if (hlpe_state != hdmi_connector_status_disconnected) - hdmi_audio_suspend(ctx->had_pvt_data); + hdmi_audio_suspend(ctx->had); return 0; } @@ -540,7 +525,7 @@ static int hdmi_lpe_audio_resume(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); /* HDMI is not connected, there is no need to resume audio device */ if (hlpe_state != hdmi_connector_status_disconnected) - hdmi_audio_resume(ctx->had_pvt_data); + hdmi_audio_resume(ctx->had); return 0; } diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 518d897f1806..0d285ce8d4e6 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -648,7 +648,6 @@ struct hdmi_audio_event { bool mid_hdmi_audio_is_busy(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); int mid_hdmi_audio_setup(had_event_call_back audio_callbacks); -int mid_hdmi_audio_register(void *had_data); int mid_hdmi_audio_read(u32 reg, u32 *val); int mid_hdmi_audio_write(u32 reg, u32 val); From 45459d16867988a792a18233bdfc294492976841 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:29:56 +0100 Subject: [PATCH 09/54] ALSA: x86: Handle the error from hdmi_audio_probe() properly The error from hdmi_audio_probe() wasn't handled properly, and it may leave some resources leaked or mapped. Fix it and also clean up the error paths. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 18a2ae6796b8..0c11d82eb99b 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -422,16 +422,14 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) NULL); if (ret < 0) { dev_err(&hlpe_pdev->dev, "request_irq failed\n"); - iounmap(mmio_start); - return -ENODEV; + goto error_irq; } /* alloc and save context */ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (ctx == NULL) { - free_irq(irq, NULL); - iounmap(mmio_start); - return -ENOMEM; + ret = -ENOMEM; + goto error_ctx; } ctx->irq = irq; @@ -454,15 +452,16 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) if (pdata == NULL) { dev_err(&hlpe_pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); - kfree(ctx); - free_irq(irq, NULL); - iounmap(mmio_start); - return -ENOMEM; + ret = -ENOMEM; + goto error_probe; } platform_set_drvdata(pdev, ctx); ret = hdmi_audio_probe(pdev, &ctx->had); + if (ret < 0) + goto error_probe; + dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); /* The Audio driver is loading now and we need to notify @@ -483,6 +482,14 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) spin_unlock_irqrestore(&pdata->lpe_audio_slock, flag_irq); return ret; + + error_probe: + kfree(ctx); + error_ctx: + free_irq(irq, NULL); + error_irq: + iounmap(mmio_start); + return ret; } /** From dd895f2e9b013a5387372dbf3a7d8405aaeb494e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:31:29 +0100 Subject: [PATCH 10/54] ALSA: x86: Drop useless mutex at probe had_mutex is (supposedly) used to protect the concurrent calls of hdmi_audio_probe(). But we may have only one device at most, so it's utterly useless. Drop it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 45ba16e27323..7165f14d5229 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -37,8 +37,6 @@ #include #include "intel_hdmi_audio.h" -static DEFINE_MUTEX(had_mutex); - /*standard module options for ALSA. This module supports only one card*/ static int hdmi_card_index = SNDRV_DEFAULT_IDX1; static char *hdmi_card_id = SNDRV_DEFAULT_STR1; @@ -1621,7 +1619,7 @@ int hdmi_audio_probe(struct platform_device *devptr, pr_err("querying display driver APIs failed %#x\n", retval); goto free_hadstream; } - mutex_lock(&had_mutex); + spin_lock_init(&intelhaddata->had_spinlock); intelhaddata->drv_status = HAD_DRV_DISCONNECTED; pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", @@ -1632,7 +1630,7 @@ int hdmi_audio_probe(struct platform_device *devptr, THIS_MODULE, 0, &card); if (retval) - goto unlock_mutex; + goto free_hadstream; intelhaddata->card = card; intelhaddata->card_id = hdmi_card_id; intelhaddata->card_index = card->number; @@ -1705,16 +1703,12 @@ int hdmi_audio_probe(struct platform_device *devptr, pm_runtime_set_active(intelhaddata->dev); pm_runtime_enable(intelhaddata->dev); - mutex_unlock(&had_mutex); - intelhaddata->hw_silence = 1; *had_ret = intelhaddata; return 0; err: snd_card_free(card); -unlock_mutex: - mutex_unlock(&had_mutex); free_hadstream: kfree(had_stream); pm_runtime_disable(intelhaddata->dev); From 437af8f2946231ee141bc2a8d37063a8bb6047b0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:38:00 +0100 Subject: [PATCH 11/54] ALSA: x86: Call event callback directly Currently the driver calls the event callback stored in its ctx pointer, but it's obviously inefficient. Replace it with the direct calls. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 11 ----------- sound/x86/intel_hdmi_audio.h | 4 ---- sound/x86/intel_hdmi_lpe_audio.c | 17 +---------------- sound/x86/intel_hdmi_lpe_audio.h | 4 ---- 4 files changed, 1 insertion(+), 35 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 7165f14d5229..571ec07a3611 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1591,7 +1591,6 @@ int hdmi_audio_probe(struct platform_device *devptr, int retval; struct snd_pcm *pcm; struct snd_card *card; - struct had_callback_ops ops_cb; struct snd_intelhad *intelhaddata; struct had_pvt_data *had_stream; @@ -1610,16 +1609,6 @@ int hdmi_audio_probe(struct platform_device *devptr, goto free_haddata; } - ops_cb.intel_had_event_call_back = had_event_handler; - - /* registering with display driver to get access to display APIs */ - - retval = mid_hdmi_audio_setup(ops_cb.intel_had_event_call_back); - if (retval) { - pr_err("querying display driver APIs failed %#x\n", retval); - goto free_hadstream; - } - spin_lock_init(&intelhaddata->had_spinlock); intelhaddata->drv_status = HAD_DRV_DISCONNECTED; pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 5a82a3f429d7..110d1d083000 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -99,10 +99,6 @@ struct had_pvt_data { enum had_status_stream stream_type; }; -struct had_callback_ops { - had_event_call_back intel_had_event_call_back; -}; - /** * struct snd_intelhad - intelhad driver structure * diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 0c11d82eb99b..54cc30f034f3 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -44,7 +44,6 @@ static union otm_hdmi_eld_t hlpe_eld; struct hdmi_lpe_audio_ctx { int irq; void __iomem *mmio_start; - had_event_call_back had_event_callbacks; struct snd_intelhad *had; int tmds_clock_speed; bool dp_output; @@ -118,8 +117,7 @@ void mid_hdmi_audio_signal_event(enum had_event_type event) /* The handler is protected in the respective * event handlers to avoid races */ - if (ctx->had_event_callbacks) - (*ctx->had_event_callbacks)(event, ctx->had); + had_event_handler(event, ctx->had); } /* @@ -257,19 +255,6 @@ int mid_hdmi_audio_set_caps(enum had_caps_list set_element, return 0; } -int mid_hdmi_audio_setup(had_event_call_back audio_callbacks) -{ - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - - dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); - - ctx->had_event_callbacks = audio_callbacks; - - return 0; -} - static void _had_wq(struct work_struct *work) { mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 0d285ce8d4e6..511bdc30dca1 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -638,16 +638,12 @@ enum had_event_type { * HDMI Display Controller Audio Interface * */ -typedef int (*had_event_call_back) (enum had_event_type event_type, - void *ctxt_info); - struct hdmi_audio_event { int type; }; bool mid_hdmi_audio_is_busy(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); -int mid_hdmi_audio_setup(had_event_call_back audio_callbacks); int mid_hdmi_audio_read(u32 reg, u32 *val); int mid_hdmi_audio_write(u32 reg, u32 val); From 033e925f68c92d058f2be67f941804e7e4f06f7c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:40:04 +0100 Subject: [PATCH 12/54] ALSA: x86: Fix possible stale interrupt calls Registering the irq handler at the too early place may cause a system stall because the irq handler may be triggered before the other initializations. Move the irq handler registration to the later point. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 54cc30f034f3..f5249b0a4ce4 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -400,16 +400,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) return -EACCES; } - /* setup interrupt handler */ - ret = request_irq(irq, display_pipe_interrupt_handler, - 0, - pdev->name, - NULL); - if (ret < 0) { - dev_err(&hlpe_pdev->dev, "request_irq failed\n"); - goto error_irq; - } - /* alloc and save context */ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (ctx == NULL) { @@ -438,11 +428,21 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) if (pdata == NULL) { dev_err(&hlpe_pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); ret = -ENOMEM; - goto error_probe; + goto error_irq; } platform_set_drvdata(pdev, ctx); + /* setup interrupt handler */ + ret = request_irq(irq, display_pipe_interrupt_handler, + 0, + pdev->name, + NULL); + if (ret < 0) { + dev_err(&hlpe_pdev->dev, "request_irq failed\n"); + goto error_irq; + } + ret = hdmi_audio_probe(pdev, &ctx->had); if (ret < 0) goto error_probe; @@ -469,10 +469,10 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) return ret; error_probe: - kfree(ctx); - error_ctx: free_irq(irq, NULL); error_irq: + kfree(ctx); + error_ctx: iounmap(mmio_start); return ret; } From af3e5c9c5d370e262da97fb8a8310a9d578efa0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:44:00 +0100 Subject: [PATCH 13/54] ALSA: x86: Drop unused mid_hdmi_audio_is_busy() The function is nowhere used. Kill it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 23 ----------------------- sound/x86/intel_hdmi_lpe_audio.h | 1 - 2 files changed, 24 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index f5249b0a4ce4..452128a941cb 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -83,29 +83,6 @@ static struct hdmi_lpe_audio_ctx *get_hdmi_context(void) return ctx; } -/* - * return whether HDMI audio device is busy. - */ -bool mid_hdmi_audio_is_busy(void *ddev) -{ - struct hdmi_lpe_audio_ctx *ctx; - int hdmi_audio_busy = 0; - struct hdmi_audio_event hdmi_audio_event; - - dev_dbg(&hlpe_pdev->dev, "%s: Enter", __func__); - - ctx = platform_get_drvdata(hlpe_pdev); - - if (hlpe_state == hdmi_connector_status_disconnected) { - /* HDMI is not connected, assuming audio device is idle. */ - return false; - } - - hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; - hdmi_audio_busy = hdmi_audio_query(ctx->had, hdmi_audio_event); - return hdmi_audio_busy != 0; -} - void mid_hdmi_audio_signal_event(enum had_event_type event) { struct hdmi_lpe_audio_ctx *ctx; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 511bdc30dca1..a1c3aa0fbc57 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -642,7 +642,6 @@ struct hdmi_audio_event { int type; }; -bool mid_hdmi_audio_is_busy(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); int mid_hdmi_audio_read(u32 reg, u32 *val); From bf8b24f8169096050795b552a778faaac349c73c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 18:09:01 +0100 Subject: [PATCH 14/54] ALSA: x86: Drop the global platform device reference Instead of referring to the global hlpe_pdev variable, pass the platform device object to each function properly. Accessing to the global object is really ugly and error-prone. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 15 ++-- sound/x86/intel_hdmi_lpe_audio.c | 146 ++++++++++++++----------------- sound/x86/intel_hdmi_lpe_audio.h | 17 ++-- 3 files changed, 87 insertions(+), 91 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 571ec07a3611..ed9db2ebe9cf 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -172,11 +172,12 @@ int had_get_hwstate(struct snd_intelhad *intelhaddata) int had_get_caps(struct snd_intelhad *intelhaddata, enum had_caps_list query, void *caps) { + struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); if (!retval) - retval = mid_hdmi_audio_get_caps(query, caps); + retval = mid_hdmi_audio_get_caps(pdev, query, caps); return retval; } @@ -184,33 +185,36 @@ int had_get_caps(struct snd_intelhad *intelhaddata, int had_set_caps(struct snd_intelhad *intelhaddata, enum had_caps_list set_element, void *caps) { + struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); if (!retval) - retval = mid_hdmi_audio_set_caps(set_element, caps); + retval = mid_hdmi_audio_set_caps(pdev, set_element, caps); return retval; } int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) { + struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); if (!retval) - retval = mid_hdmi_audio_read(offset, data); + retval = mid_hdmi_audio_read(pdev, offset, data); return retval; } int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) { + struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); if (!retval) - retval = mid_hdmi_audio_write(offset, data); + retval = mid_hdmi_audio_write(pdev, offset, data); return retval; } @@ -218,11 +222,12 @@ int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, u32 data, u32 mask) { + struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); if (!retval) - retval = mid_hdmi_audio_rmw(offset, data, mask); + retval = mid_hdmi_audio_rmw(pdev, offset, data, mask); return retval; } diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 452128a941cb..09c21346071c 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -37,11 +37,11 @@ #include "intel_hdmi_audio.h" /* globals*/ -static struct platform_device *hlpe_pdev; static int hlpe_state; static union otm_hdmi_eld_t hlpe_eld; struct hdmi_lpe_audio_ctx { + struct platform_device *pdev; int irq; void __iomem *mmio_start; struct snd_intelhad *had; @@ -74,22 +74,12 @@ static int hdmi_get_eld(void *eld) return 0; } - -static struct hdmi_lpe_audio_ctx *get_hdmi_context(void) +static void mid_hdmi_audio_signal_event(struct platform_device *pdev, + enum had_event_type event) { - struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - ctx = platform_get_drvdata(hlpe_pdev); - return ctx; -} - -void mid_hdmi_audio_signal_event(enum had_event_type event) -{ - struct hdmi_lpe_audio_ctx *ctx; - - dev_dbg(&hlpe_pdev->dev, "%s: Enter\n", __func__); - - ctx = platform_get_drvdata(hlpe_pdev); + dev_dbg(&pdev->dev, "%s: Enter\n", __func__); /* The handler is protected in the respective * event handlers to avoid races @@ -100,13 +90,11 @@ void mid_hdmi_audio_signal_event(enum had_event_type event) /* * used to write into display controller HDMI audio registers. */ -int mid_hdmi_audio_write(u32 reg, u32 val) +int mid_hdmi_audio_write(struct platform_device *pdev, u32 reg, u32 val) { - struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - ctx = platform_get_drvdata(hlpe_pdev); - - dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val); + dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val); if (ctx->dp_output) { if (reg == AUD_CONFIG && (val & AUD_CONFIG_VALID_BIT)) @@ -121,13 +109,12 @@ int mid_hdmi_audio_write(u32 reg, u32 val) * used to get the register value read from * display controller HDMI audio registers. */ -int mid_hdmi_audio_read(u32 reg, u32 *val) +int mid_hdmi_audio_read(struct platform_device *pdev, u32 reg, u32 *val) { - struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - ctx = platform_get_drvdata(hlpe_pdev); *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); - dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val); + dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val); return 0; } @@ -135,13 +122,12 @@ int mid_hdmi_audio_read(u32 reg, u32 *val) * used to update the masked bits in display controller HDMI * audio registers. */ -int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask) +int mid_hdmi_audio_rmw(struct platform_device *pdev, + u32 reg, u32 val, u32 mask) { - struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); u32 val_tmp = 0; - ctx = platform_get_drvdata(hlpe_pdev); - val_tmp = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); val_tmp &= ~mask; val_tmp |= (val & mask); @@ -152,7 +138,7 @@ int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask) } iowrite32(val_tmp, ctx->mmio_start + ctx->had_config_offset + reg); - dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, + dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val_tmp); return 0; @@ -162,15 +148,14 @@ int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask) * used to return the HDMI audio capabilities. * e.g. resolution, frame rate. */ -int mid_hdmi_audio_get_caps(enum had_caps_list get_element, +int mid_hdmi_audio_get_caps(struct platform_device *pdev, + enum had_caps_list get_element, void *capabilities) { - struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); int ret = 0; - ctx = get_hdmi_context(); - - dev_dbg(&hlpe_pdev->dev, "%s: Enter\n", __func__); + dev_dbg(&pdev->dev, "%s: Enter\n", __func__); switch (get_element) { case HAD_GET_ELD: @@ -179,18 +164,18 @@ int mid_hdmi_audio_get_caps(enum had_caps_list get_element, case HAD_GET_DISPLAY_RATE: /* ToDo: Verify if sampling freq logic is correct */ *(u32 *)capabilities = ctx->tmds_clock_speed; - dev_dbg(&hlpe_pdev->dev, "%s: tmds_clock_speed = 0x%x\n", + dev_dbg(&pdev->dev, "%s: tmds_clock_speed = 0x%x\n", __func__, ctx->tmds_clock_speed); break; case HAD_GET_LINK_RATE: /* ToDo: Verify if sampling freq logic is correct */ *(u32 *)capabilities = ctx->link_rate; - dev_dbg(&hlpe_pdev->dev, "%s: link rate = 0x%x\n", + dev_dbg(&pdev->dev, "%s: link rate = 0x%x\n", __func__, ctx->link_rate); break; case HAD_GET_DP_OUTPUT: *(u32 *)capabilities = ctx->dp_output; - dev_dbg(&hlpe_pdev->dev, "%s: dp_output = %d\n", + dev_dbg(&pdev->dev, "%s: dp_output = %d\n", __func__, ctx->dp_output); break; default: @@ -204,25 +189,25 @@ int mid_hdmi_audio_get_caps(enum had_caps_list get_element, * used to set the HDMI audio capabilities. * e.g. Audio INT. */ -int mid_hdmi_audio_set_caps(enum had_caps_list set_element, +int mid_hdmi_audio_set_caps(struct platform_device *pdev, + enum had_caps_list set_element, void *capabilties) { - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - - dev_dbg(&hlpe_pdev->dev, "%s: cap_id = 0x%x\n", __func__, set_element); + dev_dbg(&pdev->dev, "%s: cap_id = 0x%x\n", __func__, set_element); switch (set_element) { case HAD_SET_ENABLE_AUDIO_INT: { u32 status_reg; - mid_hdmi_audio_read(AUD_HDMI_STATUS_v2, &status_reg); + mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2, + &status_reg); status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; - mid_hdmi_audio_write(AUD_HDMI_STATUS_v2, status_reg); - mid_hdmi_audio_read(AUD_HDMI_STATUS_v2, &status_reg); + mid_hdmi_audio_write(pdev, AUD_HDMI_STATUS_v2, + status_reg); + mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2, + &status_reg); } break; default: @@ -234,31 +219,34 @@ int mid_hdmi_audio_set_caps(enum had_caps_list set_element, static void _had_wq(struct work_struct *work) { - mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); + struct hdmi_lpe_audio_ctx *ctx = + container_of(work, struct hdmi_lpe_audio_ctx, hdmi_audio_wq); + + mid_hdmi_audio_signal_event(ctx->pdev, HAD_EVENT_HOT_PLUG); } static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { + struct platform_device *pdev = dev_id; u32 audio_stat, audio_reg; - struct hdmi_lpe_audio_ctx *ctx; - dev_dbg(&hlpe_pdev->dev, "%s: Enter\n", __func__); + dev_dbg(&pdev->dev, "%s: Enter\n", __func__); - ctx = platform_get_drvdata(hlpe_pdev); + ctx = platform_get_drvdata(pdev); audio_reg = AUD_HDMI_STATUS_v2; - mid_hdmi_audio_read(audio_reg, &audio_stat); + mid_hdmi_audio_read(pdev, audio_reg, &audio_stat); if (audio_stat & HDMI_AUDIO_UNDERRUN) { - mid_hdmi_audio_write(audio_reg, HDMI_AUDIO_UNDERRUN); - mid_hdmi_audio_signal_event( + mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_UNDERRUN); + mid_hdmi_audio_signal_event(pdev, HAD_EVENT_AUDIO_BUFFER_UNDERRUN); } if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { - mid_hdmi_audio_write(audio_reg, HDMI_AUDIO_BUFFER_DONE); - mid_hdmi_audio_signal_event( + mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_BUFFER_DONE); + mid_hdmi_audio_signal_event(pdev, HAD_EVENT_AUDIO_BUFFER_DONE); } @@ -280,7 +268,7 @@ static void notify_audio_lpe(struct platform_device *pdev) hlpe_state = hdmi_connector_status_disconnected; - mid_hdmi_audio_signal_event( + mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_UNPLUG); } else dev_dbg(&pdev->dev, "%s: Already Unplugged!\n", @@ -307,7 +295,7 @@ static void notify_audio_lpe(struct platform_device *pdev) hdmi_set_eld(eld->eld_data); - mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); + mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_PLUG); hlpe_state = hdmi_connector_status_connected; @@ -318,7 +306,8 @@ static void notify_audio_lpe(struct platform_device *pdev) ctx->tmds_clock_speed = pdata->tmds_clock_speed; ctx->dp_output = pdata->dp_output; ctx->link_rate = pdata->link_rate; - mid_hdmi_audio_signal_event(HAD_EVENT_MODE_CHANGING); + mid_hdmi_audio_signal_event(pdev, + HAD_EVENT_MODE_CHANGING); } } } @@ -347,33 +336,32 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) {} }; - dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); + dev_dbg(&pdev->dev, "Enter %s\n", __func__); /*TBD:remove globals*/ - hlpe_pdev = pdev; hlpe_state = hdmi_connector_status_disconnected; /* get resources */ irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&hlpe_pdev->dev, "Could not get irq resource\n"); + dev_err(&pdev->dev, "Could not get irq resource\n"); return -ENODEV; } res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_mmio) { - dev_err(&hlpe_pdev->dev, "Could not get IO_MEM resources\n"); + dev_err(&pdev->dev, "Could not get IO_MEM resources\n"); return -ENXIO; } - dev_dbg(&hlpe_pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n", + dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n", __func__, (unsigned int)res_mmio->start, (unsigned int)res_mmio->end); mmio_start = ioremap_nocache(res_mmio->start, (size_t)(resource_size(res_mmio))); if (!mmio_start) { - dev_err(&hlpe_pdev->dev, "Could not get ioremap\n"); + dev_err(&pdev->dev, "Could not get ioremap\n"); return -EACCES; } @@ -384,17 +372,18 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) goto error_ctx; } + ctx->pdev = pdev; ctx->irq = irq; - dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: irq num = %d\n", irq); + dev_dbg(&pdev->dev, "hdmi lpe audio: irq num = %d\n", irq); ctx->mmio_start = mmio_start; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); if (pci_dev_present(cherryview_ids)) - dev_dbg(&hlpe_pdev->dev, "%s: Cherrytrail LPE - Detected\n", + dev_dbg(&pdev->dev, "%s: Cherrytrail LPE - Detected\n", __func__); else - dev_dbg(&hlpe_pdev->dev, "%s: Baytrail LPE - Assume\n", + dev_dbg(&pdev->dev, "%s: Baytrail LPE - Assume\n", __func__); /* assume pipe A as default */ @@ -403,7 +392,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (pdata == NULL) { - dev_err(&hlpe_pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); + dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); ret = -ENOMEM; goto error_irq; } @@ -411,12 +400,11 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); /* setup interrupt handler */ - ret = request_irq(irq, display_pipe_interrupt_handler, - 0, - pdev->name, - NULL); + ret = request_irq(irq, display_pipe_interrupt_handler, 0, + pdev->name, pdev); + if (ret < 0) { - dev_err(&hlpe_pdev->dev, "request_irq failed\n"); + dev_err(&pdev->dev, "request_irq failed\n"); goto error_irq; } @@ -424,12 +412,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) if (ret < 0) goto error_probe; - dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); + dev_dbg(&pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); /* The Audio driver is loading now and we need to notify * it if there is an HDMI device attached */ - dev_dbg(&hlpe_pdev->dev, "%s: Scheduling HDMI audio work queue\n", + dev_dbg(&pdev->dev, "%s: Scheduling HDMI audio work queue\n", __func__); schedule_work(&ctx->hdmi_audio_wq); @@ -437,7 +425,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) pdata->notify_audio_lpe = notify_audio_lpe; if (pdata->notify_pending) { - dev_dbg(&hlpe_pdev->dev, "%s: handle pending notification\n", __func__); + dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); notify_audio_lpe(pdev); pdata->notify_pending = false; } @@ -446,7 +434,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) return ret; error_probe: - free_irq(irq, NULL); + free_irq(irq, pdev); error_irq: kfree(ctx); error_ctx: @@ -464,13 +452,13 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); + dev_dbg(&pdev->dev, "Enter %s\n", __func__); hdmi_audio_remove(ctx->had); /* release resources */ iounmap(ctx->mmio_start); - free_irq(ctx->irq, NULL); + free_irq(ctx->irq, pdev); kfree(ctx); return 0; } diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index a1c3aa0fbc57..a9d51b7c5bae 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -31,6 +31,8 @@ #include #include +struct platform_device; + #define AUD_CONFIG_VALID_BIT (1<<9) #define AUD_CONFIG_DP_MODE (1<<15) #define AUD_CONFIG_BLOCK_BIT (1<<7) @@ -642,15 +644,16 @@ struct hdmi_audio_event { int type; }; -void mid_hdmi_audio_signal_event(enum had_event_type event); +int mid_hdmi_audio_read(struct platform_device *pdev, u32 reg, u32 *val); +int mid_hdmi_audio_write(struct platform_device *pdev, u32 reg, u32 val); +int mid_hdmi_audio_rmw(struct platform_device *pdev, + u32 reg, u32 val, u32 mask); -int mid_hdmi_audio_read(u32 reg, u32 *val); -int mid_hdmi_audio_write(u32 reg, u32 val); -int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask); - -int mid_hdmi_audio_get_caps(enum had_caps_list get_element, +int mid_hdmi_audio_get_caps(struct platform_device *pdev, + enum had_caps_list get_element, void *capabilities); -int mid_hdmi_audio_set_caps(enum had_caps_list set_element, +int mid_hdmi_audio_set_caps(struct platform_device *pdev, + enum had_caps_list set_element, void *capabilties); #endif From 055610b002c1066b8ca1919b8d051d80c9e2d86e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 18:11:13 +0100 Subject: [PATCH 15/54] ALSA: x86: Drop global hlpe_state Now it's the turn to drop the global hlpe_state variable. It can be gracefully embedded in hdmi_lpe_audio_ctx struct. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 09c21346071c..775a8b947213 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -37,7 +37,6 @@ #include "intel_hdmi_audio.h" /* globals*/ -static int hlpe_state; static union otm_hdmi_eld_t hlpe_eld; struct hdmi_lpe_audio_ctx { @@ -51,6 +50,7 @@ struct hdmi_lpe_audio_ctx { unsigned int had_config_offset; int hdmi_audio_interrupt_mask; struct work_struct hdmi_audio_wq; + int state; /* connection state */ }; static void hdmi_set_eld(void *eld) @@ -263,10 +263,9 @@ static void notify_audio_lpe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", __func__); - if (hlpe_state == hdmi_connector_status_connected) { + if (ctx->state == hdmi_connector_status_connected) { - hlpe_state = - hdmi_connector_status_disconnected; + ctx->state = hdmi_connector_status_disconnected; mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_UNPLUG); @@ -297,7 +296,7 @@ static void notify_audio_lpe(struct platform_device *pdev) mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_PLUG); - hlpe_state = hdmi_connector_status_connected; + ctx->state = hdmi_connector_status_connected; dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", __func__, eld->port_id, pdata->tmds_clock_speed); @@ -338,9 +337,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Enter %s\n", __func__); - /*TBD:remove globals*/ - hlpe_state = hdmi_connector_status_disconnected; - /* get resources */ irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -378,6 +374,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->mmio_start = mmio_start; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); + ctx->state = hdmi_connector_status_disconnected; if (pci_dev_present(cherryview_ids)) dev_dbg(&pdev->dev, "%s: Cherrytrail LPE - Detected\n", @@ -468,9 +465,9 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, { struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); + dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state); /* HDMI is not connected, assuming audio device is suspended already */ - if (hlpe_state != hdmi_connector_status_disconnected) + if (ctx->state != hdmi_connector_status_disconnected) hdmi_audio_suspend(ctx->had); return 0; } @@ -479,9 +476,9 @@ static int hdmi_lpe_audio_resume(struct platform_device *pdev) { struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); + dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state); /* HDMI is not connected, there is no need to resume audio device */ - if (hlpe_state != hdmi_connector_status_disconnected) + if (ctx->state != hdmi_connector_status_disconnected) hdmi_audio_resume(ctx->had); return 0; } From 7f2e9ab5a2e1afcedd1e50650670c309e46822ac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 18:15:40 +0100 Subject: [PATCH 16/54] ALSA: x86: Drop global ELD copy Similarly like the previous patch, drop the global variable to keep the ELD copy. It can be embedded in hdmi_lpe_audio_ctx as well. And this makes easier to code, it's just a memcpy(), after all. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 775a8b947213..53864d372861 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -36,9 +36,6 @@ #include "intel_hdmi_lpe_audio.h" #include "intel_hdmi_audio.h" -/* globals*/ -static union otm_hdmi_eld_t hlpe_eld; - struct hdmi_lpe_audio_ctx { struct platform_device *pdev; int irq; @@ -51,29 +48,9 @@ struct hdmi_lpe_audio_ctx { int hdmi_audio_interrupt_mask; struct work_struct hdmi_audio_wq; int state; /* connection state */ + union otm_hdmi_eld_t eld; /* ELD copy */ }; -static void hdmi_set_eld(void *eld) -{ - int size; - - BUILD_BUG_ON(sizeof(hlpe_eld) > HDMI_MAX_ELD_BYTES); - - size = sizeof(hlpe_eld); - memcpy((void *)&hlpe_eld, eld, size); -} - -static int hdmi_get_eld(void *eld) -{ - u8 *eld_data = (u8 *)&hlpe_eld; - - memcpy(eld, (void *)&hlpe_eld, sizeof(hlpe_eld)); - - print_hex_dump_bytes("eld: ", DUMP_PREFIX_NONE, eld_data, - sizeof(hlpe_eld)); - return 0; -} - static void mid_hdmi_audio_signal_event(struct platform_device *pdev, enum had_event_type event) { @@ -159,7 +136,9 @@ int mid_hdmi_audio_get_caps(struct platform_device *pdev, switch (get_element) { case HAD_GET_ELD: - ret = hdmi_get_eld(capabilities); + memcpy(capabilities, &ctx->eld, sizeof(ctx->eld)); + print_hex_dump_bytes("eld: ", DUMP_PREFIX_NONE, + (u8 *)&ctx->eld, sizeof(ctx->eld)); break; case HAD_GET_DISPLAY_RATE: /* ToDo: Verify if sampling freq logic is correct */ @@ -292,7 +271,7 @@ static void notify_audio_lpe(struct platform_device *pdev) break; } - hdmi_set_eld(eld->eld_data); + memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld)); mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_PLUG); From 6ddb3ab66f94109c524859ba4dd9d43772893676 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 18:17:44 +0100 Subject: [PATCH 17/54] ALSA: x86: Move the global underrun_count to struct snd_intelhad The last one is in intel_hdmi_audio.c, underrun_count: this can be embedded in snd_intelhad object. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 15 +++++++-------- sound/x86/intel_hdmi_audio.h | 2 ++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index ed9db2ebe9cf..e08691110a48 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -40,7 +40,6 @@ /*standard module options for ALSA. This module supports only one card*/ static int hdmi_card_index = SNDRV_DEFAULT_IDX1; static char *hdmi_card_id = SNDRV_DEFAULT_STR1; -static int underrun_count; module_param_named(index, hdmi_card_index, int, 0444); MODULE_PARM_DESC(index, @@ -969,7 +968,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); had_stream = intelhaddata->private_data; runtime = substream->runtime; - underrun_count = 0; + intelhaddata->underrun_count = 0; pm_runtime_get(intelhaddata->dev); @@ -1376,19 +1375,19 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t); if ((t == 0) || (t == ((u32)-1L))) { - underrun_count++; + intelhaddata->underrun_count++; pr_debug("discovered buffer done for buf %d, count = %d\n", - buf_id, underrun_count); + buf_id, intelhaddata->underrun_count); - if (underrun_count > (HAD_MIN_PERIODS/2)) { + if (intelhaddata->underrun_count > (HAD_MIN_PERIODS/2)) { pr_debug("assume audio_codec_reset, underrun = %d - do xrun\n", - underrun_count); - underrun_count = 0; + intelhaddata->underrun_count); + intelhaddata->underrun_count = 0; return SNDRV_PCM_POS_XRUN; } } else { /* Reset Counter */ - underrun_count = 0; + intelhaddata->underrun_count = 0; } t = intelhaddata->buf_info[buf_id].buf_size - t; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 110d1d083000..da0a927d37fe 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -119,6 +119,7 @@ struct had_pvt_data { * @chmap: holds channel map info * @audio_reg_base: hdmi audio register base offset * @hw_silence: flag indicates SoC support for HW silence/Keep alive + * @underrun_count: PCM stream underrun counter */ struct snd_intelhad { struct snd_card *card; @@ -142,6 +143,7 @@ struct snd_intelhad { unsigned int *audio_reg_base; unsigned int audio_cfg_offset; bool hw_silence; + int underrun_count; }; int had_event_handler(enum had_event_type event_type, void *data); From 0e18060f99a42c20f87d64eb30e5f424509643ae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 07:53:56 +0100 Subject: [PATCH 18/54] ALSA: x86: Drop unused hw_silence field It's nowhere used. Let's drop it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 1 - sound/x86/intel_hdmi_audio.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index e08691110a48..efc56544af17 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1696,7 +1696,6 @@ int hdmi_audio_probe(struct platform_device *devptr, pm_runtime_set_active(intelhaddata->dev); pm_runtime_enable(intelhaddata->dev); - intelhaddata->hw_silence = 1; *had_ret = intelhaddata; return 0; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index da0a927d37fe..32a2fb766e47 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -118,7 +118,6 @@ struct had_pvt_data { * @kctl: holds kctl ptrs used for channel map * @chmap: holds channel map info * @audio_reg_base: hdmi audio register base offset - * @hw_silence: flag indicates SoC support for HW silence/Keep alive * @underrun_count: PCM stream underrun counter */ struct snd_intelhad { @@ -142,7 +141,6 @@ struct snd_intelhad { struct snd_pcm_chmap *chmap; unsigned int *audio_reg_base; unsigned int audio_cfg_offset; - bool hw_silence; int underrun_count; }; From dae15a9d960e513d5b60c00c306cddd87465f1c4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:02:16 +0100 Subject: [PATCH 19/54] ALSA: x86: Move dma_mask debug print into intel_hdmi_lpe_audio.c It belongs to the right place. And, remove a few sanity checks (e.g. NULL card) and debug prints as well. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 11 ----------- sound/x86/intel_hdmi_lpe_audio.c | 1 + 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index efc56544af17..49cb95072a88 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1600,8 +1600,6 @@ int hdmi_audio_probe(struct platform_device *devptr, pr_debug("Enter %s\n", __func__); - pr_debug("hdmi_audio_probe dma_mask: %p\n", devptr->dev.dma_mask); - /* allocate memory for saving internal context and working */ intelhaddata = kzalloc(sizeof(*intelhaddata), GFP_KERNEL); if (!intelhaddata) @@ -1653,15 +1651,6 @@ int hdmi_audio_probe(struct platform_device *devptr, retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, NULL, HAD_MAX_BUFFER, HAD_MAX_BUFFER); - - if (card->dev == NULL) - pr_debug("card->dev is NULL!!!!! Should not be this case\n"); - else if (card->dev->dma_mask == NULL) - pr_debug("hdmi_audio_probe dma_mask is NULL!!!!!\n"); - else - pr_debug("hdmi_audio_probe dma_mask is : %p\n", - card->dev->dma_mask); - if (retval) goto err; diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 53864d372861..6f823d4278bb 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -315,6 +315,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) }; dev_dbg(&pdev->dev, "Enter %s\n", __func__); + dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); /* get resources */ irq = platform_get_irq(pdev, 0); From 5647aec26640ffdf099d51b3403eaeac10d74147 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:14:34 +0100 Subject: [PATCH 20/54] ALSA: x86: Embed snd_intelhad into snd_card Instead of allocating snd_intelhad struct, use the card's private_data and embed it. It simplifies the code a lot. While we're at it, embed had_stream into snd_intelhad struct instead of individually allocating, and rename had_pvt_data to a bit more specific name, had_stream_data. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 77 ++++++--------------------------- sound/x86/intel_hdmi_audio.h | 4 +- sound/x86/intel_hdmi_audio_if.c | 32 +++++++------- 3 files changed, 31 insertions(+), 82 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 49cb95072a88..dfc4452afee1 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -961,12 +961,12 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; struct had_stream_pvt *stream; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; int retval; pr_debug("snd_intelhad_open called\n"); intelhaddata = snd_pcm_substream_chip(substream); - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; runtime = substream->runtime; intelhaddata->underrun_count = 0; @@ -1180,13 +1180,13 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, unsigned long flag_irq; struct snd_intelhad *intelhaddata; struct had_stream_pvt *stream; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; pr_debug("snd_intelhad_pcm_trigger called\n"); intelhaddata = snd_pcm_substream_chip(substream); stream = substream->runtime->private_data; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1262,13 +1262,13 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) u32 link_rate = 0; struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; pr_debug("snd_intelhad_pcm_prepare called\n"); intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; if (had_get_hwstate(intelhaddata)) { pr_err("%s: HDMI cable plugged-out\n", __func__); @@ -1479,31 +1479,6 @@ struct snd_pcm_ops snd_intelhad_playback_ops = { .mmap = snd_intelhad_pcm_mmap, }; -/** - * snd_intelhad_create - to crete alsa card instance - * - * @intelhaddata: pointer to internal context - * @card: pointer to card - * - * This function is called when the hdmi cable is plugged in - */ -static int snd_intelhad_create( - struct snd_intelhad *intelhaddata, - struct snd_card *card) -{ - int retval; - static struct snd_device_ops ops = { - }; - - pr_debug("snd_intelhad_create called\n"); - - if (!intelhaddata) - return -EINVAL; - - /* ALSA api to register the device */ - retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, intelhaddata, &ops); - return retval; -} /** * snd_intelhad_pcm_free - to free the memory allocated * @@ -1596,36 +1571,24 @@ int hdmi_audio_probe(struct platform_device *devptr, struct snd_pcm *pcm; struct snd_card *card; struct snd_intelhad *intelhaddata; - struct had_pvt_data *had_stream; pr_debug("Enter %s\n", __func__); - /* allocate memory for saving internal context and working */ - intelhaddata = kzalloc(sizeof(*intelhaddata), GFP_KERNEL); - if (!intelhaddata) - return -ENOMEM; - - had_stream = kzalloc(sizeof(*had_stream), GFP_KERNEL); - if (!had_stream) { - retval = -ENOMEM; - goto free_haddata; - } + /* create a card instance with ALSA framework */ + retval = snd_card_new(&devptr->dev, hdmi_card_index, hdmi_card_id, + THIS_MODULE, sizeof(*intelhaddata), &card); + if (retval) + return retval; + intelhaddata = card->private_data; spin_lock_init(&intelhaddata->had_spinlock); intelhaddata->drv_status = HAD_DRV_DISCONNECTED; pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); - /* create a card instance with ALSA framework */ - retval = snd_card_new(&devptr->dev, hdmi_card_index, hdmi_card_id, - THIS_MODULE, 0, &card); - - if (retval) - goto free_hadstream; intelhaddata->card = card; intelhaddata->card_id = hdmi_card_id; intelhaddata->card_index = card->number; - intelhaddata->private_data = had_stream; intelhaddata->flag_underrun = 0; intelhaddata->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; strncpy(card->driver, INTEL_HAD, strlen(INTEL_HAD)); @@ -1654,12 +1617,6 @@ int hdmi_audio_probe(struct platform_device *devptr, if (retval) goto err; - /* internal function call to register device with ALSA */ - retval = snd_intelhad_create(intelhaddata, card); - if (retval) - goto err; - - card->private_data = &intelhaddata; retval = snd_card_register(card); if (retval) goto err; @@ -1688,15 +1645,9 @@ int hdmi_audio_probe(struct platform_device *devptr, *had_ret = intelhaddata; return 0; + err: snd_card_free(card); -free_hadstream: - kfree(had_stream); - pm_runtime_disable(intelhaddata->dev); - intelhaddata->dev = NULL; -free_haddata: - kfree(intelhaddata); - intelhaddata = NULL; pr_err("Error returned from %s api %#x\n", __func__, retval); return retval; } @@ -1724,8 +1675,6 @@ int hdmi_audio_remove(struct snd_intelhad *intelhaddata) had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); } snd_card_free(intelhaddata->card); - kfree(intelhaddata->private_data); - kfree(intelhaddata); return 0; } diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 32a2fb766e47..98a004499f3c 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -95,7 +95,7 @@ struct had_stream_pvt { ssize_t dbg_cum_bytes; }; -struct had_pvt_data { +struct had_stream_data { enum had_status_stream stream_type; }; @@ -133,7 +133,7 @@ struct snd_intelhad { int valid_buf_cnt; unsigned int aes_bits; int flag_underrun; - struct had_pvt_data *private_data; + struct had_stream_data stream_data; spinlock_t had_spinlock; enum intel_had_aud_buf_type buff_done; struct device *dev; diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 8e3a0943332b..caf982e55ec6 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -45,13 +45,13 @@ int hdmi_audio_query(void *haddata, struct hdmi_audio_event event) { struct snd_pcm_substream *substream = NULL; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; if (intelhaddata->stream_info.had_substream) substream = intelhaddata->stream_info.had_substream; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; switch (event.type) { case HAD_EVENT_QUERY_IS_AUDIO_BUSY: spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); @@ -98,14 +98,14 @@ int hdmi_audio_query(void *haddata, struct hdmi_audio_event event) int hdmi_audio_suspend(void *haddata) { int caps, retval = 0; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; struct snd_pcm_substream *substream; struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; pr_debug("Enter:%s\n", __func__); - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; substream = intelhaddata->stream_info.had_substream; if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { @@ -199,10 +199,10 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, int i, intr_count = 0; enum intel_had_aud_buf_type buff_done; u32 buf_size, buf_addr; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; buff_done = buf_id; @@ -244,12 +244,12 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata) enum intel_had_aud_buf_type buff_done; struct pcm_stream_info *stream; u32 buf_size; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; int intr_count; enum had_status_stream stream_type; unsigned long flag_irqs; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; intr_count = 1; @@ -331,12 +331,12 @@ int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct pcm_stream_info *stream; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; enum had_status_stream stream_type; unsigned long flag_irqs; int drv_status; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); @@ -372,13 +372,13 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; pr_debug("Enter:%s\n", __func__); substream = intelhaddata->stream_info.had_substream; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { @@ -413,12 +413,12 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) { int caps, retval = 0; enum intel_had_aud_buf_type buf_id; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; pr_debug("Enter:%s\n", __func__); - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; buf_id = intelhaddata->curr_buf; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); @@ -476,11 +476,11 @@ int had_event_handler(enum had_event_type event_type, void *data) struct snd_intelhad *intelhaddata = data; enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; buf_id = intelhaddata->curr_buf; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; /* Switching to a function can drop atomicity even in INTR context. * Thus, a big lock is acquired to maintain atomicity. From c415022e487fbba19926b56b981c5474474c0465 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:42:50 +0100 Subject: [PATCH 21/54] ALSA: x86: Drop superfluous CHT PCI ID check Since the config base offset is now set per pipe id, we don't have to check Cherry Trail PCI IDs any longer. Currently it's used only for debug prints. Let's drop it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 6f823d4278bb..b84f7d92ed24 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -306,13 +306,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) void __iomem *mmio_start; int ret = 0; unsigned long flag_irq; - static const struct pci_device_id cherryview_ids[] = { - {PCI_DEVICE(0x8086, 0x22b0)}, - {PCI_DEVICE(0x8086, 0x22b1)}, - {PCI_DEVICE(0x8086, 0x22b2)}, - {PCI_DEVICE(0x8086, 0x22b3)}, - {} - }; dev_dbg(&pdev->dev, "Enter %s\n", __func__); dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); @@ -356,13 +349,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); ctx->state = hdmi_connector_status_disconnected; - if (pci_dev_present(cherryview_ids)) - dev_dbg(&pdev->dev, "%s: Cherrytrail LPE - Detected\n", - __func__); - else - dev_dbg(&pdev->dev, "%s: Baytrail LPE - Assume\n", - __func__); - /* assume pipe A as default */ ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; From 301cf8a9559bb372ab64da3781d3d93d1ce38213 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:44:23 +0100 Subject: [PATCH 22/54] ALSA: x86: Check platform_data earlier Just a minor optimization; check the presence of platform_data earlier in the probe function before actually starting allocation, which makes the error path easier. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index b84f7d92ed24..8789f55724da 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -310,6 +310,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Enter %s\n", __func__); dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); + return -EINVAL; + } + /* get resources */ irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -352,14 +358,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) /* assume pipe A as default */ ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; - pdata = pdev->dev.platform_data; - - if (pdata == NULL) { - dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); - ret = -ENOMEM; - goto error_irq; - } - platform_set_drvdata(pdev, ctx); /* setup interrupt handler */ From 36ec0d99bbd7bb392bf64059cbda1818ee2be5a2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:47:05 +0100 Subject: [PATCH 23/54] ALSA: x86: Call snd_card_register() at the end The card registration should be done at the last stage of the probe procedure. Otherwise user-space may access to the device before the whole initialization is done. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index dfc4452afee1..82f42a6c363c 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1586,6 +1586,7 @@ int hdmi_audio_probe(struct platform_device *devptr, pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); + intelhaddata->dev = &devptr->dev; intelhaddata->card = card; intelhaddata->card_id = hdmi_card_id; intelhaddata->card_index = card->number; @@ -1617,10 +1618,6 @@ int hdmi_audio_probe(struct platform_device *devptr, if (retval) goto err; - retval = snd_card_register(card); - if (retval) - goto err; - /* IEC958 controls */ retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask, intelhaddata)); @@ -1638,7 +1635,10 @@ int hdmi_audio_probe(struct platform_device *devptr, if (retval < 0) goto err; - intelhaddata->dev = &devptr->dev; + retval = snd_card_register(card); + if (retval) + goto err; + pm_runtime_set_active(intelhaddata->dev); pm_runtime_enable(intelhaddata->dev); From eeb756c5bf7566fd79312798a32f59e594688b79 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 11:06:34 +0100 Subject: [PATCH 24/54] ALSA: x86: Drop unused hdmi_audio_query() It's used nowhere. Kill it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.h | 1 - sound/x86/intel_hdmi_audio_if.c | 54 --------------------------------- 2 files changed, 55 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 98a004499f3c..8415f93e40dc 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -146,7 +146,6 @@ struct snd_intelhad { int had_event_handler(enum had_event_type event_type, void *data); -int hdmi_audio_query(void *drv_data, struct hdmi_audio_event event); int hdmi_audio_suspend(void *drv_data); int hdmi_audio_resume(void *drv_data); int hdmi_audio_mode_change(struct snd_pcm_substream *substream); diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index caf982e55ec6..57acefaf930e 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -33,60 +33,6 @@ #include "intel_hdmi_audio.h" #include "intel_hdmi_lpe_audio.h" -/** - * hdmi_audio_query - hdmi audio query function - * - *@haddata: pointer to HAD private data - *@event: audio event for which this method is invoked - * - * This function is called by client driver to query the - * hdmi audio. - */ -int hdmi_audio_query(void *haddata, struct hdmi_audio_event event) -{ - struct snd_pcm_substream *substream = NULL; - struct had_stream_data *had_stream; - unsigned long flag_irqs; - struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; - - if (intelhaddata->stream_info.had_substream) - substream = intelhaddata->stream_info.had_substream; - had_stream = &intelhaddata->stream_data; - switch (event.type) { - case HAD_EVENT_QUERY_IS_AUDIO_BUSY: - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - - if ((had_stream->stream_type == HAD_RUNNING_STREAM) || - substream) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, - flag_irqs); - pr_debug("Audio stream active\n"); - return -EBUSY; - } - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - break; - - case HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED: - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, - flag_irqs); - pr_debug("Audio is suspended\n"); - return 1; - } - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - break; - - default: - pr_debug("error un-handled event !!\n"); - return -EINVAL; - break; - - } - - return 0; -} - /** * hdmi_audio_suspend - power management suspend function * From da8648097497505d05d8cff6892351f99c029791 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 13:52:22 +0100 Subject: [PATCH 25/54] ALSA: x86: Flatten two abstraction layers This is the final stage for a big clean-up series. Here we flatten the two layers into one. Formerly, the implementation was split to HDMI "shell" that talks with the platform device, and HDMI audio part that communicates via caps and other event handlers. All these would be good if there were multiple instantiations or if there were data protection. But neither are true in our case. That said, it'll be easier to have a flat driver structure in the end. In this patch, the former struct hdmi_lpe_audio_ctx is forged into the existing struct snd_intelhad. The latter has already a few members that are basically the copy from the former. Only a few new members for the lowlevel I/O are added by this change. Then, the had_get_caps() and had_set_caps() are simply replaced with the direct calls to copy the data in the struct fields. Also, the had_event_handler() calls are replaced with the direct call for each event as well. Signed-off-by: Takashi Iwai --- sound/x86/Makefile | 3 +- sound/x86/intel_hdmi_audio.c | 482 ++++++++++++++++++++----------- sound/x86/intel_hdmi_audio.h | 37 ++- sound/x86/intel_hdmi_audio_if.c | 128 ++------ sound/x86/intel_hdmi_lpe_audio.c | 462 ----------------------------- sound/x86/intel_hdmi_lpe_audio.h | 23 +- 6 files changed, 361 insertions(+), 774 deletions(-) delete mode 100644 sound/x86/intel_hdmi_lpe_audio.c diff --git a/sound/x86/Makefile b/sound/x86/Makefile index 85ea22a2cf28..3c0bf63333e6 100644 --- a/sound/x86/Makefile +++ b/sound/x86/Makefile @@ -1,6 +1,5 @@ snd-hdmi-lpe-audio-objs += \ intel_hdmi_audio.o \ - intel_hdmi_audio_if.o \ - intel_hdmi_lpe_audio.o + intel_hdmi_audio_if.o obj-$(CONFIG_HDMI_LPE_AUDIO) += snd-hdmi-lpe-audio.o diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 82f42a6c363c..1594f826cf31 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #include "intel_hdmi_audio.h" /*standard module options for ALSA. This module supports only one card*/ @@ -168,72 +170,75 @@ int had_get_hwstate(struct snd_intelhad *intelhaddata) return 0; } -int had_get_caps(struct snd_intelhad *intelhaddata, - enum had_caps_list query, void *caps) +static inline void +mid_hdmi_audio_read(struct snd_intelhad *ctx, u32 reg, u32 *val) { - struct platform_device *pdev = to_platform_device(intelhaddata->dev); - int retval; - - retval = had_get_hwstate(intelhaddata); - if (!retval) - retval = mid_hdmi_audio_get_caps(pdev, query, caps); - - return retval; + *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); } -int had_set_caps(struct snd_intelhad *intelhaddata, - enum had_caps_list set_element, void *caps) +static inline void +mid_hdmi_audio_write(struct snd_intelhad *ctx, u32 reg, u32 val) { - struct platform_device *pdev = to_platform_device(intelhaddata->dev); - int retval; - - retval = had_get_hwstate(intelhaddata); - if (!retval) - retval = mid_hdmi_audio_set_caps(pdev, set_element, caps); - - return retval; + iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); } int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) { - struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); - if (!retval) - retval = mid_hdmi_audio_read(pdev, offset, data); + if (retval) + return retval; - return retval; + mid_hdmi_audio_read(intelhaddata, offset, data); + return 0; +} + +static void fixup_dp_config(struct snd_intelhad *intelhaddata, + u32 offset, u32 *data) +{ + if (intelhaddata->dp_output) { + if (offset == AUD_CONFIG && (*data & AUD_CONFIG_VALID_BIT)) + *data |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; + } } int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) { - struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); - if (!retval) - retval = mid_hdmi_audio_write(pdev, offset, data); + if (retval) + return retval; - return retval; + fixup_dp_config(intelhaddata, offset, &data); + mid_hdmi_audio_write(intelhaddata, offset, data); + return 0; } int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, u32 data, u32 mask) { - struct platform_device *pdev = to_platform_device(intelhaddata->dev); + u32 val_tmp; int retval; retval = had_get_hwstate(intelhaddata); - if (!retval) - retval = mid_hdmi_audio_rmw(pdev, offset, data, mask); + if (retval) + return retval; - return retval; + mid_hdmi_audio_read(intelhaddata, offset, &val_tmp); + val_tmp &= ~mask; + val_tmp |= (data & mask); + + fixup_dp_config(intelhaddata, offset, &val_tmp); + mid_hdmi_audio_write(intelhaddata, offset, val_tmp); + return 0; } -/** - * function to read-modify - * AUD_CONFIG register on VLV2.The had_read_modify() function should not - * directly be used on VLV2 for updating AUD_CONFIG register. + +/* + * function to read-modify AUD_CONFIG register on VLV2. + * The had_read_modify() function should not directly be used on VLV2 for + * updating AUD_CONFIG register. * This is because: * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2 * HDMI IP. As a result a read-modify of AUD_CONFIG regiter will always @@ -249,10 +254,10 @@ int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, * @mask : mask * */ -static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, +static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata, u32 data, u32 mask) { - struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); + struct snd_pcm_substream *substream; union aud_cfg cfg_val = {.cfg_regval = 0}; u8 channels; @@ -260,7 +265,8 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, * If substream is NULL, there is no active stream. * In this case just set channels to 2 */ - if (substream) + substream = intelhaddata->stream_info.had_substream; + if (substream && substream->runtime) channels = substream->runtime->channels; else channels = 2; @@ -274,9 +280,23 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, return had_read_modify(intelhaddata, AUD_CONFIG, data, mask); } -void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable) +void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) { - had_read_modify_aud_config_v2(substream, enable, BIT(0)); + u32 status_reg; + + if (enable) { + mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS_v2, &status_reg); + status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; + mid_hdmi_audio_write(ctx, AUD_HDMI_STATUS_v2, status_reg); + mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS_v2, &status_reg); + } +} + +void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata, + bool enable) +{ + had_read_modify_aud_config_v2(intelhaddata, enable ? BIT(0) : 0, + BIT(0)); } static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, @@ -437,7 +457,7 @@ static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata, */ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (intelhaddata->eeld.speaker_allocation_block & (1 << i)) + if (intelhaddata->eld.speaker_allocation_block & (1 << i)) spk_mask |= eld_speaker_allocation_bits[i]; } @@ -482,11 +502,8 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) return; } - had_get_caps(intelhaddata, HAD_GET_ELD, &intelhaddata->eeld); - had_get_caps(intelhaddata, HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); - - pr_debug("eeld.speaker_allocation_block = %x\n", - intelhaddata->eeld.speaker_allocation_block); + pr_debug("eld.speaker_allocation_block = %x\n", + intelhaddata->eld.speaker_allocation_block); /* WA: Fix the max channel supported to 8 */ @@ -497,14 +514,14 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) */ /* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */ - eld_high = intelhaddata->eeld.speaker_allocation_block & eld_high_mask; + eld_high = intelhaddata->eld.speaker_allocation_block & eld_high_mask; if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) { /* eld_high & (eld_high-1): if more than 1 bit set */ /* 0x1F: 7 channels */ for (i = 1; i < 4; i++) { high_msb = eld_high & (0x80 >> i); if (high_msb) { - intelhaddata->eeld.speaker_allocation_block &= + intelhaddata->eld.speaker_allocation_block &= high_msb | 0xF; break; } @@ -512,7 +529,7 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) } for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (intelhaddata->eeld.speaker_allocation_block & (1 << i)) + if (intelhaddata->eld.speaker_allocation_block & (1 << i)) spk_mask |= eld_speaker_allocation_bits[i]; } @@ -1176,7 +1193,7 @@ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - int caps, retval = 0; + int retval = 0; unsigned long flag_irq; struct snd_intelhad *intelhaddata; struct had_stream_pvt *stream; @@ -1203,15 +1220,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, had_stream->stream_type = HAD_RUNNING_STREAM; /* Enable Audio */ - /* - * ToDo: Need to enable UNDERRUN interrupts as well - * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - */ - caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO_INT, - &caps); - retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO, NULL); - snd_intelhad_enable_audio(substream, 1); + snd_intelhad_enable_audio_int(intelhaddata, true); + snd_intelhad_enable_audio(intelhaddata, true); pr_debug("Processed _Start\n"); @@ -1228,18 +1238,13 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, had_stream->stream_type = HAD_INIT; spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq); /* Disable Audio */ - /* - * ToDo: Need to disable UNDERRUN interrupts as well - * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - */ - caps = HDMI_AUDIO_BUFFER_DONE; - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); - snd_intelhad_enable_audio(substream, 0); + snd_intelhad_enable_audio_int(intelhaddata, false); + snd_intelhad_enable_audio(intelhaddata, false); /* Reset buffer pointers */ snd_intelhad_reset_audio(intelhaddata, 1); snd_intelhad_reset_audio(intelhaddata, 0); stream->stream_status = STREAM_DROPPED; - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); + snd_intelhad_enable_audio_int(intelhaddata, false); break; default: @@ -1297,15 +1302,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) /* Get N value in KHz */ - retval = had_get_caps(intelhaddata, HAD_GET_DISPLAY_RATE, - &disp_samp_freq); - if (retval) { - pr_err("querying display sampling freq failed %#x\n", retval); - goto prep_end; - } - - had_get_caps(intelhaddata, HAD_GET_ELD, &intelhaddata->eeld); - had_get_caps(intelhaddata, HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); + disp_samp_freq = intelhaddata->tmds_clock_speed; retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, intelhaddata); @@ -1315,8 +1312,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) } if (intelhaddata->dp_output) - had_get_caps(intelhaddata, HAD_GET_LINK_RATE, &link_rate); - + link_rate = intelhaddata->link_rate; snd_intelhad_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate, @@ -1425,25 +1421,22 @@ static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, vma->vm_end - vma->vm_start, vma->vm_page_prot); } -int hdmi_audio_mode_change(struct snd_pcm_substream *substream) +static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) { + struct snd_pcm_substream *substream; int retval = 0; u32 disp_samp_freq, n_param; u32 link_rate = 0; - struct snd_intelhad *intelhaddata; - intelhaddata = snd_pcm_substream_chip(substream); + substream = intelhaddata->stream_info.had_substream; + if (!substream || !substream->runtime) + return 0; /* Disable Audio */ - snd_intelhad_enable_audio(substream, 0); + snd_intelhad_enable_audio(intelhaddata, false); /* Update CTS value */ - retval = had_get_caps(intelhaddata, HAD_GET_DISPLAY_RATE, - &disp_samp_freq); - if (retval) { - pr_err("querying display sampling freq failed %#x\n", retval); - goto out; - } + disp_samp_freq = intelhaddata->tmds_clock_speed; retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, intelhaddata); @@ -1453,14 +1446,14 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) } if (intelhaddata->dp_output) - had_get_caps(intelhaddata, HAD_GET_LINK_RATE, &link_rate); + link_rate = intelhaddata->link_rate; snd_intelhad_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate, n_param, intelhaddata); /* Enable Audio */ - snd_intelhad_enable_audio(substream, 1); + snd_intelhad_enable_audio(intelhaddata, true); out: return retval; @@ -1555,129 +1548,290 @@ static struct snd_kcontrol_new had_control_iec958 = { .put = had_iec958_put }; -/* - * hdmi_audio_probe - to create sound card instance for HDMI audio playabck - * - * @devptr: platform device - * @had_ret: pointer to store the created snd_intelhad object - * - * This function is called when the platform device is probed. This function - * creates and registers the sound card with ALSA - */ -int hdmi_audio_probe(struct platform_device *devptr, - struct snd_intelhad **had_ret) +static void _had_wq(struct work_struct *work) { - int retval; - struct snd_pcm *pcm; - struct snd_card *card; - struct snd_intelhad *intelhaddata; + struct snd_intelhad *ctx = + container_of(work, struct snd_intelhad, hdmi_audio_wq); - pr_debug("Enter %s\n", __func__); + had_process_hot_plug(ctx); +} + +static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) +{ + struct snd_intelhad *ctx = dev_id; + u32 audio_stat, audio_reg; + + audio_reg = AUD_HDMI_STATUS_v2; + mid_hdmi_audio_read(ctx, audio_reg, &audio_stat); + + if (audio_stat & HDMI_AUDIO_UNDERRUN) { + mid_hdmi_audio_write(ctx, audio_reg, HDMI_AUDIO_UNDERRUN); + had_process_buffer_underrun(ctx); + } + + if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { + mid_hdmi_audio_write(ctx, audio_reg, HDMI_AUDIO_BUFFER_DONE); + had_process_buffer_done(ctx); + } + + return IRQ_HANDLED; +} + +static void notify_audio_lpe(struct platform_device *pdev) +{ + struct snd_intelhad *ctx = platform_get_drvdata(pdev); + struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data; + + if (pdata->hdmi_connected != true) { + + dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", + __func__); + + if (ctx->state == hdmi_connector_status_connected) { + + ctx->state = hdmi_connector_status_disconnected; + + had_process_hot_unplug(ctx); + } else + dev_dbg(&pdev->dev, "%s: Already Unplugged!\n", + __func__); + + } else { + struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; + + switch (eld->pipe_id) { + case 0: + ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; + break; + case 1: + ctx->had_config_offset = AUDIO_HDMI_CONFIG_B; + break; + case 2: + ctx->had_config_offset = AUDIO_HDMI_CONFIG_C; + break; + default: + dev_dbg(&pdev->dev, "Invalid pipe %d\n", + eld->pipe_id); + break; + } + + memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld)); + + had_process_hot_plug(ctx); + + ctx->state = hdmi_connector_status_connected; + + dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", + __func__, eld->port_id, pdata->tmds_clock_speed); + + if (pdata->tmds_clock_speed) { + ctx->tmds_clock_speed = pdata->tmds_clock_speed; + ctx->dp_output = pdata->dp_output; + ctx->link_rate = pdata->link_rate; + + /* Process mode change if stream is active */ + if (ctx->stream_data.stream_type == HAD_RUNNING_STREAM) + hdmi_audio_mode_change(ctx); + } + } +} + +/* release resources */ +static void hdmi_lpe_audio_free(struct snd_card *card) +{ + struct snd_intelhad *ctx = card->private_data; + + if (ctx->mmio_start) + iounmap(ctx->mmio_start); + if (ctx->irq >= 0) + free_irq(ctx->irq, ctx); +} + +/* + * hdmi_lpe_audio_probe - start bridge with i915 + * + * This function is called when the i915 driver creates the + * hdmi-lpe-audio platform device. Card creation is deferred until a + * hot plug event is received + */ +static int hdmi_lpe_audio_probe(struct platform_device *pdev) +{ + struct snd_card *card; + struct snd_intelhad *ctx; + struct snd_pcm *pcm; + struct intel_hdmi_lpe_audio_pdata *pdata; + int irq; + struct resource *res_mmio; + int ret; + unsigned long flags; + + dev_dbg(&pdev->dev, "Enter %s\n", __func__); + dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); + return -EINVAL; + } + + /* get resources */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "Could not get irq resource\n"); + return -ENODEV; + } + + res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mmio) { + dev_err(&pdev->dev, "Could not get IO_MEM resources\n"); + return -ENXIO; + } /* create a card instance with ALSA framework */ - retval = snd_card_new(&devptr->dev, hdmi_card_index, hdmi_card_id, - THIS_MODULE, sizeof(*intelhaddata), &card); - if (retval) - return retval; + ret = snd_card_new(&pdev->dev, hdmi_card_index, hdmi_card_id, + THIS_MODULE, sizeof(*ctx), &card); + if (ret) + return ret; - intelhaddata = card->private_data; - spin_lock_init(&intelhaddata->had_spinlock); - intelhaddata->drv_status = HAD_DRV_DISCONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", - __func__, __LINE__); + ctx = card->private_data; + spin_lock_init(&ctx->had_spinlock); + ctx->drv_status = HAD_DRV_DISCONNECTED; + ctx->dev = &pdev->dev; + ctx->card = card; + ctx->card_id = hdmi_card_id; + ctx->card_index = card->number; + ctx->flag_underrun = 0; + ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; + strcpy(card->driver, INTEL_HAD); + strcpy(card->shortname, INTEL_HAD); - intelhaddata->dev = &devptr->dev; - intelhaddata->card = card; - intelhaddata->card_id = hdmi_card_id; - intelhaddata->card_index = card->number; - intelhaddata->flag_underrun = 0; - intelhaddata->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; - strncpy(card->driver, INTEL_HAD, strlen(INTEL_HAD)); - strncpy(card->shortname, INTEL_HAD, strlen(INTEL_HAD)); + ctx->irq = -1; + ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; + INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); + ctx->state = hdmi_connector_status_disconnected; - retval = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS, - MAX_CAP_STREAMS, &pcm); - if (retval) + card->private_free = hdmi_lpe_audio_free; + + /* assume pipe A as default */ + ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; + + platform_set_drvdata(pdev, ctx); + + dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n", + __func__, (unsigned int)res_mmio->start, + (unsigned int)res_mmio->end); + + ctx->mmio_start = ioremap_nocache(res_mmio->start, + (size_t)(resource_size(res_mmio))); + if (!ctx->mmio_start) { + dev_err(&pdev->dev, "Could not get ioremap\n"); + ret = -EACCES; + goto err; + } + + /* setup interrupt handler */ + ret = request_irq(irq, display_pipe_interrupt_handler, 0, + pdev->name, ctx); + if (ret < 0) { + dev_err(&pdev->dev, "request_irq failed\n"); + goto err; + } + + ctx->irq = irq; + + ret = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS, + MAX_CAP_STREAMS, &pcm); + if (ret) goto err; /* setup private data which can be retrieved when required */ - pcm->private_data = intelhaddata; + pcm->private_data = ctx; pcm->private_free = snd_intelhad_pcm_free; pcm->info_flags = 0; strncpy(pcm->name, card->shortname, strlen(card->shortname)); - /* setup the ops for palyabck */ + /* setup the ops for playabck */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intelhad_playback_ops); /* allocate dma pages for ALSA stream operations * memory allocated is based on size, not max value * thus using same argument for max & size */ - retval = snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, NULL, HAD_MAX_BUFFER, HAD_MAX_BUFFER); - if (retval) - goto err; /* IEC958 controls */ - retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask, - intelhaddata)); - if (retval < 0) + ret = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask, ctx)); + if (ret < 0) goto err; - retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958, - intelhaddata)); - if (retval < 0) + ret = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958, ctx)); + if (ret < 0) goto err; init_channel_allocations(); /* Register channel map controls */ - retval = had_register_chmap_ctls(intelhaddata, pcm); - if (retval < 0) + ret = had_register_chmap_ctls(ctx, pcm); + if (ret < 0) goto err; - retval = snd_card_register(card); - if (retval) + ret = snd_card_register(card); + if (ret) goto err; - pm_runtime_set_active(intelhaddata->dev); - pm_runtime_enable(intelhaddata->dev); + spin_lock_irqsave(&pdata->lpe_audio_slock, flags); + pdata->notify_audio_lpe = notify_audio_lpe; + if (pdata->notify_pending) { - *had_ret = intelhaddata; + dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); + notify_audio_lpe(pdev); + pdata->notify_pending = false; + } + spin_unlock_irqrestore(&pdata->lpe_audio_slock, flags); + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + schedule_work(&ctx->hdmi_audio_wq); return 0; err: snd_card_free(card); - pr_err("Error returned from %s api %#x\n", __func__, retval); - return retval; + return ret; } /* - * hdmi_audio_remove - removes the alsa card + * hdmi_lpe_audio_remove - stop bridge with i915 * - *@haddata: pointer to HAD private data - * - * This function is called when the hdmi cable is un-plugged. This function - * free the sound card. + * This function is called when the platform device is destroyed. The sound + * card should have been removed on hot plug event. */ -int hdmi_audio_remove(struct snd_intelhad *intelhaddata) +static int hdmi_lpe_audio_remove(struct platform_device *pdev) { - int caps; + struct snd_intelhad *ctx = platform_get_drvdata(pdev); - pr_debug("Enter %s\n", __func__); + dev_dbg(&pdev->dev, "Enter %s\n", __func__); - if (!intelhaddata) - return 0; - - if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { - caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); - } - snd_card_free(intelhaddata->card); + if (ctx->drv_status != HAD_DRV_DISCONNECTED) + snd_intelhad_enable_audio_int(ctx, false); + snd_card_free(ctx->card); return 0; } +static struct platform_driver hdmi_lpe_audio_driver = { + .driver = { + .name = "hdmi-lpe-audio", + }, + .probe = hdmi_lpe_audio_probe, + .remove = hdmi_lpe_audio_remove, + .suspend = hdmi_lpe_audio_suspend, + .resume = hdmi_lpe_audio_resume +}; + +module_platform_driver(hdmi_lpe_audio_driver); +MODULE_ALIAS("platform:hdmi_lpe_audio"); + MODULE_AUTHOR("Sailaja Bandarupalli "); MODULE_AUTHOR("Ramesh Babu K V "); MODULE_AUTHOR("Vaibhav Agarwal "); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 8415f93e40dc..6efa846f98c9 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -108,7 +108,7 @@ struct had_stream_data { * @drv_status: driver status * @buf_info: ring buffer info * @stream_info: stream information - * @eeld: holds EELD info + * @eld: holds ELD info * @curr_buf: pointer to hold current active ring buf * @valid_buf_cnt: ring buffer count for stream * @had_spinlock: driver lock @@ -127,7 +127,7 @@ struct snd_intelhad { enum had_drv_status drv_status; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; - union otm_hdmi_eld_t eeld; + union otm_hdmi_eld_t eld; bool dp_output; enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; @@ -142,15 +142,27 @@ struct snd_intelhad { unsigned int *audio_reg_base; unsigned int audio_cfg_offset; int underrun_count; + enum hdmi_connector_status state; + int tmds_clock_speed; + int link_rate; + + /* internal stuff */ + int irq; + void __iomem *mmio_start; + unsigned int had_config_offset; + int hdmi_audio_interrupt_mask; + struct work_struct hdmi_audio_wq; }; -int had_event_handler(enum had_event_type event_type, void *data); - -int hdmi_audio_suspend(void *drv_data); -int hdmi_audio_resume(void *drv_data); -int hdmi_audio_mode_change(struct snd_pcm_substream *substream); +int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state); +int hdmi_lpe_audio_resume(struct platform_device *pdev); extern struct snd_pcm_ops snd_intelhad_playback_ops; +int had_process_buffer_done(struct snd_intelhad *intelhaddata); +int had_process_buffer_underrun(struct snd_intelhad *intelhaddata); +int had_process_hot_plug(struct snd_intelhad *intelhaddata); +int had_process_hot_unplug(struct snd_intelhad *intelhaddata); + int snd_intelhad_init_audio_ctrl(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata, int flag_silence); @@ -160,15 +172,12 @@ int snd_intelhad_invd_buffer(int start, int end); int snd_intelhad_read_len(struct snd_intelhad *intelhaddata); void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata); -void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable); +void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable); +void snd_intelhad_enable_audio(struct snd_intelhad *ctx, bool enable); void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata); /* Register access functions */ int had_get_hwstate(struct snd_intelhad *intelhaddata); -int had_get_caps(struct snd_intelhad *intelhaddata, - enum had_caps_list query_element, void *capabilties); -int had_set_caps(struct snd_intelhad *intelhaddata, - enum had_caps_list set_element, void *capabilties); int had_read_register(struct snd_intelhad *intelhaddata, u32 reg_addr, u32 *data); int had_write_register(struct snd_intelhad *intelhaddata, @@ -176,8 +185,4 @@ int had_write_register(struct snd_intelhad *intelhaddata, int had_read_modify(struct snd_intelhad *intelhaddata, u32 reg_addr, u32 data, u32 mask); -int hdmi_audio_probe(struct platform_device *devptr, - struct snd_intelhad **had_ret); -int hdmi_audio_remove(struct snd_intelhad *intelhaddata); - #endif /* _INTEL_HDMI_AUDIO_ */ diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 57acefaf930e..327650dd1723 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -33,21 +33,20 @@ #include "intel_hdmi_audio.h" #include "intel_hdmi_lpe_audio.h" -/** - * hdmi_audio_suspend - power management suspend function +/* + * hdmi_lpe_audio_suspend - power management suspend function * - *@haddata: pointer to HAD private data + * @pdev: platform device * * This function is called by client driver to suspend the * hdmi audio. */ -int hdmi_audio_suspend(void *haddata) +int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state) { - int caps, retval = 0; struct had_stream_data *had_stream; unsigned long flag_irqs; struct snd_pcm_substream *substream; - struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; + struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); pr_debug("Enter:%s\n", __func__); @@ -64,13 +63,13 @@ int hdmi_audio_suspend(void *haddata) if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); pr_debug("had not connected\n"); - return retval; + return 0; } if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); pr_debug("had already suspended\n"); - return retval; + return 0; } intelhaddata->drv_status = HAD_DRV_SUSPENDED; @@ -78,29 +77,22 @@ int hdmi_audio_suspend(void *haddata) __func__, __LINE__); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - /* - * ToDo: Need to disable UNDERRUN interrupts as well - * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - */ - caps = HDMI_AUDIO_BUFFER_DONE; - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); + snd_intelhad_enable_audio_int(intelhaddata, false); pr_debug("Exit:%s", __func__); - return retval; + return 0; } -/** - * hdmi_audio_resume - power management resume function +/* + * hdmi_lpe_audio_resume - power management resume function * - *@haddata: pointer to HAD private data + *@pdev: platform device * * This function is called by client driver to resume the * hdmi audio. */ -int hdmi_audio_resume(void *haddata) +int hdmi_lpe_audio_resume(struct platform_device *pdev) { - int caps, retval = 0; - struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; + struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); unsigned long flag_irqs; pr_debug("Enter:%s\n", __func__); @@ -128,15 +120,9 @@ int hdmi_audio_resume(void *haddata) pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - /* - * ToDo: Need to enable UNDERRUN interrupts as well - * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - */ - caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO_INT, &caps); - retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO, NULL); + snd_intelhad_enable_audio_int(intelhaddata, true); pr_debug("Exit:%s", __func__); - return retval; + return 0; } static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, @@ -357,7 +343,6 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata) int had_process_hot_unplug(struct snd_intelhad *intelhaddata) { - int caps, retval = 0; enum intel_had_aud_buf_type buf_id; struct had_stream_data *had_stream; unsigned long flag_irqs; @@ -372,17 +357,12 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { pr_debug("Device already disconnected\n"); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - return retval; + return 0; } else { /* Disable Audio */ - caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, - &caps); - retval = had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, - NULL); - snd_intelhad_enable_audio( - intelhaddata->stream_info.had_substream, 0); + snd_intelhad_enable_audio_int(intelhaddata, false); + snd_intelhad_enable_audio(intelhaddata, false); } intelhaddata->drv_status = HAD_DRV_DISCONNECTED; @@ -405,74 +385,6 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) intelhaddata->audio_reg_base = NULL; pr_debug("%s: unlocked -> returned\n", __func__); - return retval; + return 0; } -/** - * had_event_handler - Call back function to handle events - * - * @event_type: Event type to handle - * @data: data related to the event_type - * - * This function is invoked to handle HDMI events from client driver. - */ -int had_event_handler(enum had_event_type event_type, void *data) -{ - int retval = 0; - struct snd_intelhad *intelhaddata = data; - enum intel_had_aud_buf_type buf_id; - struct snd_pcm_substream *substream; - struct had_stream_data *had_stream; - unsigned long flag_irqs; - - buf_id = intelhaddata->curr_buf; - had_stream = &intelhaddata->stream_data; - - /* Switching to a function can drop atomicity even in INTR context. - * Thus, a big lock is acquired to maintain atomicity. - * This can be optimized later. - * Currently, only buffer_done/_underrun executes in INTR context. - * Also, locking is implemented separately to avoid real contention - * of data(struct intelhaddata) between IRQ/SOFT_IRQ/PROCESS context. - */ - substream = intelhaddata->stream_info.had_substream; - switch (event_type) { - case HAD_EVENT_AUDIO_BUFFER_DONE: - retval = had_process_buffer_done(intelhaddata); - break; - - case HAD_EVENT_AUDIO_BUFFER_UNDERRUN: - retval = had_process_buffer_underrun(intelhaddata); - break; - - case HAD_EVENT_HOT_PLUG: - retval = had_process_hot_plug(intelhaddata); - break; - - case HAD_EVENT_HOT_UNPLUG: - retval = had_process_hot_unplug(intelhaddata); - break; - - case HAD_EVENT_MODE_CHANGING: - pr_debug(" called _event_handler with _MODE_CHANGE event\n"); - /* Process only if stream is active & cable Plugged-in */ - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status >= HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, - flag_irqs); - break; - } - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - if ((had_stream->stream_type == HAD_RUNNING_STREAM) - && substream) - retval = hdmi_audio_mode_change(substream); - break; - - default: - pr_debug("error un-handled event !!\n"); - retval = -EINVAL; - break; - - } - return retval; -} diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c deleted file mode 100644 index 8789f55724da..000000000000 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * intel_hdmi_lpe_audio.c - Intel HDMI LPE audio driver for Atom platforms - * - * Copyright (C) 2016 Intel Corp - * Authors: - * Jerome Anand - * Aravind Siddappaji - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "intel_hdmi_lpe_audio.h" -#include "intel_hdmi_audio.h" - -struct hdmi_lpe_audio_ctx { - struct platform_device *pdev; - int irq; - void __iomem *mmio_start; - struct snd_intelhad *had; - int tmds_clock_speed; - bool dp_output; - int link_rate; - unsigned int had_config_offset; - int hdmi_audio_interrupt_mask; - struct work_struct hdmi_audio_wq; - int state; /* connection state */ - union otm_hdmi_eld_t eld; /* ELD copy */ -}; - -static void mid_hdmi_audio_signal_event(struct platform_device *pdev, - enum had_event_type event) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "%s: Enter\n", __func__); - - /* The handler is protected in the respective - * event handlers to avoid races - */ - had_event_handler(event, ctx->had); -} - -/* - * used to write into display controller HDMI audio registers. - */ -int mid_hdmi_audio_write(struct platform_device *pdev, u32 reg, u32 val) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val); - - if (ctx->dp_output) { - if (reg == AUD_CONFIG && (val & AUD_CONFIG_VALID_BIT)) - val |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; - } - iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); - - return 0; -} - -/* - * used to get the register value read from - * display controller HDMI audio registers. - */ -int mid_hdmi_audio_read(struct platform_device *pdev, u32 reg, u32 *val) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); - dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val); - return 0; -} - -/* - * used to update the masked bits in display controller HDMI - * audio registers. - */ -int mid_hdmi_audio_rmw(struct platform_device *pdev, - u32 reg, u32 val, u32 mask) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - u32 val_tmp = 0; - - val_tmp = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); - val_tmp &= ~mask; - val_tmp |= (val & mask); - - if (ctx->dp_output) { - if (reg == AUD_CONFIG && (val_tmp & AUD_CONFIG_VALID_BIT)) - val_tmp |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; - } - - iowrite32(val_tmp, ctx->mmio_start + ctx->had_config_offset + reg); - dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, - reg, val_tmp); - - return 0; -} - -/* - * used to return the HDMI audio capabilities. - * e.g. resolution, frame rate. - */ -int mid_hdmi_audio_get_caps(struct platform_device *pdev, - enum had_caps_list get_element, - void *capabilities) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - int ret = 0; - - dev_dbg(&pdev->dev, "%s: Enter\n", __func__); - - switch (get_element) { - case HAD_GET_ELD: - memcpy(capabilities, &ctx->eld, sizeof(ctx->eld)); - print_hex_dump_bytes("eld: ", DUMP_PREFIX_NONE, - (u8 *)&ctx->eld, sizeof(ctx->eld)); - break; - case HAD_GET_DISPLAY_RATE: - /* ToDo: Verify if sampling freq logic is correct */ - *(u32 *)capabilities = ctx->tmds_clock_speed; - dev_dbg(&pdev->dev, "%s: tmds_clock_speed = 0x%x\n", - __func__, ctx->tmds_clock_speed); - break; - case HAD_GET_LINK_RATE: - /* ToDo: Verify if sampling freq logic is correct */ - *(u32 *)capabilities = ctx->link_rate; - dev_dbg(&pdev->dev, "%s: link rate = 0x%x\n", - __func__, ctx->link_rate); - break; - case HAD_GET_DP_OUTPUT: - *(u32 *)capabilities = ctx->dp_output; - dev_dbg(&pdev->dev, "%s: dp_output = %d\n", - __func__, ctx->dp_output); - break; - default: - break; - } - - return ret; -} - -/* - * used to set the HDMI audio capabilities. - * e.g. Audio INT. - */ -int mid_hdmi_audio_set_caps(struct platform_device *pdev, - enum had_caps_list set_element, - void *capabilties) -{ - dev_dbg(&pdev->dev, "%s: cap_id = 0x%x\n", __func__, set_element); - - switch (set_element) { - case HAD_SET_ENABLE_AUDIO_INT: - { - u32 status_reg; - - mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2, - &status_reg); - status_reg |= - HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; - mid_hdmi_audio_write(pdev, AUD_HDMI_STATUS_v2, - status_reg); - mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2, - &status_reg); - } - break; - default: - break; - } - - return 0; -} - -static void _had_wq(struct work_struct *work) -{ - struct hdmi_lpe_audio_ctx *ctx = - container_of(work, struct hdmi_lpe_audio_ctx, hdmi_audio_wq); - - mid_hdmi_audio_signal_event(ctx->pdev, HAD_EVENT_HOT_PLUG); -} - -static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) -{ - struct platform_device *pdev = dev_id; - u32 audio_stat, audio_reg; - struct hdmi_lpe_audio_ctx *ctx; - - dev_dbg(&pdev->dev, "%s: Enter\n", __func__); - - ctx = platform_get_drvdata(pdev); - - audio_reg = AUD_HDMI_STATUS_v2; - mid_hdmi_audio_read(pdev, audio_reg, &audio_stat); - - if (audio_stat & HDMI_AUDIO_UNDERRUN) { - mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_UNDERRUN); - mid_hdmi_audio_signal_event(pdev, - HAD_EVENT_AUDIO_BUFFER_UNDERRUN); - } - - if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { - mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_BUFFER_DONE); - mid_hdmi_audio_signal_event(pdev, - HAD_EVENT_AUDIO_BUFFER_DONE); - } - - return IRQ_HANDLED; -} - -static void notify_audio_lpe(struct platform_device *pdev) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data; - - if (pdata->hdmi_connected != true) { - - dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", - __func__); - - if (ctx->state == hdmi_connector_status_connected) { - - ctx->state = hdmi_connector_status_disconnected; - - mid_hdmi_audio_signal_event(pdev, - HAD_EVENT_HOT_UNPLUG); - } else - dev_dbg(&pdev->dev, "%s: Already Unplugged!\n", - __func__); - - } else { - struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; - - switch (eld->pipe_id) { - case 0: - ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; - break; - case 1: - ctx->had_config_offset = AUDIO_HDMI_CONFIG_B; - break; - case 2: - ctx->had_config_offset = AUDIO_HDMI_CONFIG_C; - break; - default: - dev_dbg(&pdev->dev, "Invalid pipe %d\n", - eld->pipe_id); - break; - } - - memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld)); - - mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_PLUG); - - ctx->state = hdmi_connector_status_connected; - - dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", - __func__, eld->port_id, pdata->tmds_clock_speed); - - if (pdata->tmds_clock_speed) { - ctx->tmds_clock_speed = pdata->tmds_clock_speed; - ctx->dp_output = pdata->dp_output; - ctx->link_rate = pdata->link_rate; - mid_hdmi_audio_signal_event(pdev, - HAD_EVENT_MODE_CHANGING); - } - } -} - -/** - * hdmi_lpe_audio_probe - start bridge with i915 - * - * This function is called when the i915 driver creates the - * hdmi-lpe-audio platform device. Card creation is deferred until a - * hot plug event is received - */ -static int hdmi_lpe_audio_probe(struct platform_device *pdev) -{ - struct hdmi_lpe_audio_ctx *ctx; - struct intel_hdmi_lpe_audio_pdata *pdata; - int irq; - struct resource *res_mmio; - void __iomem *mmio_start; - int ret = 0; - unsigned long flag_irq; - - dev_dbg(&pdev->dev, "Enter %s\n", __func__); - dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); - return -EINVAL; - } - - /* get resources */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Could not get irq resource\n"); - return -ENODEV; - } - - res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res_mmio) { - dev_err(&pdev->dev, "Could not get IO_MEM resources\n"); - return -ENXIO; - } - - dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n", - __func__, (unsigned int)res_mmio->start, - (unsigned int)res_mmio->end); - - mmio_start = ioremap_nocache(res_mmio->start, - (size_t)(resource_size(res_mmio))); - if (!mmio_start) { - dev_err(&pdev->dev, "Could not get ioremap\n"); - return -EACCES; - } - - /* alloc and save context */ - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (ctx == NULL) { - ret = -ENOMEM; - goto error_ctx; - } - - ctx->pdev = pdev; - ctx->irq = irq; - dev_dbg(&pdev->dev, "hdmi lpe audio: irq num = %d\n", irq); - ctx->mmio_start = mmio_start; - ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; - INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); - ctx->state = hdmi_connector_status_disconnected; - - /* assume pipe A as default */ - ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; - - platform_set_drvdata(pdev, ctx); - - /* setup interrupt handler */ - ret = request_irq(irq, display_pipe_interrupt_handler, 0, - pdev->name, pdev); - - if (ret < 0) { - dev_err(&pdev->dev, "request_irq failed\n"); - goto error_irq; - } - - ret = hdmi_audio_probe(pdev, &ctx->had); - if (ret < 0) - goto error_probe; - - dev_dbg(&pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); - - /* The Audio driver is loading now and we need to notify - * it if there is an HDMI device attached - */ - dev_dbg(&pdev->dev, "%s: Scheduling HDMI audio work queue\n", - __func__); - schedule_work(&ctx->hdmi_audio_wq); - - spin_lock_irqsave(&pdata->lpe_audio_slock, flag_irq); - pdata->notify_audio_lpe = notify_audio_lpe; - if (pdata->notify_pending) { - - dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); - notify_audio_lpe(pdev); - pdata->notify_pending = false; - } - spin_unlock_irqrestore(&pdata->lpe_audio_slock, flag_irq); - - return ret; - - error_probe: - free_irq(irq, pdev); - error_irq: - kfree(ctx); - error_ctx: - iounmap(mmio_start); - return ret; -} - -/** - * hdmi_lpe_audio_remove - stop bridge with i915 - * - * This function is called when the platform device is destroyed. The sound - * card should have been removed on hot plug event. - */ -static int hdmi_lpe_audio_remove(struct platform_device *pdev) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "Enter %s\n", __func__); - - hdmi_audio_remove(ctx->had); - - /* release resources */ - iounmap(ctx->mmio_start); - free_irq(ctx->irq, pdev); - kfree(ctx); - return 0; -} - -static int hdmi_lpe_audio_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state); - /* HDMI is not connected, assuming audio device is suspended already */ - if (ctx->state != hdmi_connector_status_disconnected) - hdmi_audio_suspend(ctx->had); - return 0; -} - -static int hdmi_lpe_audio_resume(struct platform_device *pdev) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state); - /* HDMI is not connected, there is no need to resume audio device */ - if (ctx->state != hdmi_connector_status_disconnected) - hdmi_audio_resume(ctx->had); - return 0; -} - -static struct platform_driver hdmi_lpe_audio_driver = { - .driver = { - .name = "hdmi-lpe-audio", - }, - .probe = hdmi_lpe_audio_probe, - .remove = hdmi_lpe_audio_remove, - .suspend = hdmi_lpe_audio_suspend, - .resume = hdmi_lpe_audio_resume -}; - -module_platform_driver(hdmi_lpe_audio_driver); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:hdmi_lpe_audio"); diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index a9d51b7c5bae..8f320b4aa3b7 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -27,12 +27,11 @@ #include #include #include +#include #include #include #include -struct platform_device; - #define AUD_CONFIG_VALID_BIT (1<<9) #define AUD_CONFIG_DP_MODE (1<<15) #define AUD_CONFIG_BLOCK_BIT (1<<7) @@ -636,24 +635,4 @@ enum had_event_type { HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED, }; -/* - * HDMI Display Controller Audio Interface - * - */ -struct hdmi_audio_event { - int type; -}; - -int mid_hdmi_audio_read(struct platform_device *pdev, u32 reg, u32 *val); -int mid_hdmi_audio_write(struct platform_device *pdev, u32 reg, u32 val); -int mid_hdmi_audio_rmw(struct platform_device *pdev, - u32 reg, u32 val, u32 mask); - -int mid_hdmi_audio_get_caps(struct platform_device *pdev, - enum had_caps_list get_element, - void *capabilities); -int mid_hdmi_audio_set_caps(struct platform_device *pdev, - enum had_caps_list set_element, - void *capabilties); - #endif From 372d855f87b535005e392094afff9927bc000cf9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 13:57:58 +0100 Subject: [PATCH 26/54] ALSA: x86: Fold intel_hdmi_audio_if.c into main file As the very last step, we fold intel_hdmi_audio_if.c into the main file, intel_hdmi_audio.c. This is merely a cleanup, and no functional change. By this move, we can mark all functions and variables as static, which allows the compiler more optimizations. Signed-off-by: Takashi Iwai --- sound/x86/Makefile | 3 +- sound/x86/intel_hdmi_audio.c | 391 ++++++++++++++++++++++++++++++-- sound/x86/intel_hdmi_audio.h | 31 --- sound/x86/intel_hdmi_audio_if.c | 390 ------------------------------- 4 files changed, 376 insertions(+), 439 deletions(-) delete mode 100644 sound/x86/intel_hdmi_audio_if.c diff --git a/sound/x86/Makefile b/sound/x86/Makefile index 3c0bf63333e6..7ff919808320 100644 --- a/sound/x86/Makefile +++ b/sound/x86/Makefile @@ -1,5 +1,4 @@ snd-hdmi-lpe-audio-objs += \ - intel_hdmi_audio.o \ - intel_hdmi_audio_if.o + intel_hdmi_audio.o obj-$(CONFIG_HDMI_LPE_AUDIO) += snd-hdmi-lpe-audio.o diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 1594f826cf31..effe93b58273 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -157,8 +157,7 @@ static const struct snd_pcm_hardware snd_intel_hadstream = { }; /* Register access functions */ - -int had_get_hwstate(struct snd_intelhad *intelhaddata) +static int had_get_hwstate(struct snd_intelhad *intelhaddata) { /* Check for device presence -SW state */ if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { @@ -182,7 +181,8 @@ mid_hdmi_audio_write(struct snd_intelhad *ctx, u32 reg, u32 val) iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); } -int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) +static int had_read_register(struct snd_intelhad *intelhaddata, + u32 offset, u32 *data) { int retval; @@ -203,7 +203,8 @@ static void fixup_dp_config(struct snd_intelhad *intelhaddata, } } -int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) +static int had_write_register(struct snd_intelhad *intelhaddata, + u32 offset, u32 data) { int retval; @@ -216,8 +217,8 @@ int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) return 0; } -int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, - u32 data, u32 mask) +static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, + u32 data, u32 mask) { u32 val_tmp; int retval; @@ -280,7 +281,7 @@ static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata, return had_read_modify(intelhaddata, AUD_CONFIG, data, mask); } -void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) +static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) { u32 status_reg; @@ -292,8 +293,8 @@ void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) } } -void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata, - bool enable) +static void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata, + bool enable) { had_read_modify_aud_config_v2(intelhaddata, enable ? BIT(0) : 0, BIT(0)); @@ -488,7 +489,7 @@ static int spk_to_chmap(int spk) return 0; } -void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) +static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) { int i = 0, c = 0; int spk_mask = 0; @@ -675,7 +676,7 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, * * This function programs ring buffer address and length into registers. */ -int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, +static int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, int start, int end) { u32 ring_buf_addr, ring_buf_size, period_bytes; @@ -732,7 +733,7 @@ int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, return 0; } -int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) +static int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) { int i, retval = 0; u32 len[4]; @@ -939,7 +940,7 @@ static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, return 0; } -void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) +static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) { u32 hdmi_status, i = 0; @@ -1459,8 +1460,364 @@ out: return retval; } -/*PCM operations structure and the calls back for the same */ -struct snd_pcm_ops snd_intelhad_playback_ops = { +/* + * hdmi_lpe_audio_suspend - power management suspend function + * + * @pdev: platform device + * + * This function is called by client driver to suspend the + * hdmi audio. + */ +static int hdmi_lpe_audio_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct had_stream_data *had_stream; + unsigned long flag_irqs; + struct snd_pcm_substream *substream; + struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); + + pr_debug("Enter:%s\n", __func__); + + had_stream = &intelhaddata->stream_data; + substream = intelhaddata->stream_info.had_substream; + + if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { + pr_err("audio stream is active\n"); + return -EAGAIN; + } + + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("had not connected\n"); + return 0; + } + + if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("had already suspended\n"); + return 0; + } + + intelhaddata->drv_status = HAD_DRV_SUSPENDED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", + __func__, __LINE__); + + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + snd_intelhad_enable_audio_int(intelhaddata, false); + pr_debug("Exit:%s", __func__); + return 0; +} + +/* + * hdmi_lpe_audio_resume - power management resume function + * + *@pdev: platform device + * + * This function is called by client driver to resume the + * hdmi audio. + */ +static int hdmi_lpe_audio_resume(struct platform_device *pdev) +{ + struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); + unsigned long flag_irqs; + + pr_debug("Enter:%s\n", __func__); + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("had not connected\n"); + return 0; + } + + if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_err("had is not in suspended state\n"); + return 0; + } + + if (had_get_hwstate(intelhaddata)) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_err("Failed to resume. Device not accessible\n"); + return -ENODEV; + } + + intelhaddata->drv_status = HAD_DRV_CONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + __func__, __LINE__); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + snd_intelhad_enable_audio_int(intelhaddata, true); + pr_debug("Exit:%s", __func__); + return 0; +} + +static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, + enum intel_had_aud_buf_type buf_id) +{ + int i, intr_count = 0; + enum intel_had_aud_buf_type buff_done; + u32 buf_size, buf_addr; + struct had_stream_data *had_stream; + unsigned long flag_irqs; + + had_stream = &intelhaddata->stream_data; + + buff_done = buf_id; + + intr_count = snd_intelhad_read_len(intelhaddata); + if (intr_count > 1) { + /* In case of active playback */ + pr_err("Driver detected %d missed buffer done interrupt(s)!!!!\n", + (intr_count - 1)); + if (intr_count > 3) + return intr_count; + + buf_id += (intr_count - 1); + /* Reprogram registers*/ + for (i = buff_done; i < buf_id; i++) { + int j = i % 4; + + buf_size = intelhaddata->buf_info[j].buf_size; + buf_addr = intelhaddata->buf_info[j].buf_addr; + had_write_register(intelhaddata, + AUD_BUF_A_LENGTH + + (j * HAD_REG_WIDTH), buf_size); + had_write_register(intelhaddata, + AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH), + (buf_addr | BIT(0) | BIT(1))); + } + buf_id = buf_id % 4; + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + intelhaddata->buff_done = buf_id; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + } + + return intr_count; +} + +static int had_process_buffer_done(struct snd_intelhad *intelhaddata) +{ + u32 len = 1; + enum intel_had_aud_buf_type buf_id; + enum intel_had_aud_buf_type buff_done; + struct pcm_stream_info *stream; + u32 buf_size; + struct had_stream_data *had_stream; + int intr_count; + enum had_status_stream stream_type; + unsigned long flag_irqs; + + had_stream = &intelhaddata->stream_data; + stream = &intelhaddata->stream_info; + intr_count = 1; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_err("%s:Device already disconnected\n", __func__); + return 0; + } + buf_id = intelhaddata->curr_buf; + intelhaddata->buff_done = buf_id; + buff_done = intelhaddata->buff_done; + buf_size = intelhaddata->buf_info[buf_id].buf_size; + stream_type = had_stream->stream_type; + + pr_debug("Enter:%s buf_id=%d\n", __func__, buf_id); + + /* Every debug statement has an implication + * of ~5msec. Thus, avoid having >3 debug statements + * for each buffer_done handling. + */ + + /* Check for any intr_miss in case of active playback */ + if (had_stream->stream_type == HAD_RUNNING_STREAM) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + intr_count = had_chk_intrmiss(intelhaddata, buf_id); + if (!intr_count || (intr_count > 3)) { + pr_err("HAD SW state in non-recoverable!!! mode\n"); + pr_err("Already played stale data\n"); + return 0; + } + buf_id += (intr_count - 1); + buf_id = buf_id % 4; + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + } + + intelhaddata->buf_info[buf_id].is_valid = true; + if (intelhaddata->valid_buf_cnt-1 == buf_id) { + if (had_stream->stream_type >= HAD_RUNNING_STREAM) + intelhaddata->curr_buf = HAD_BUF_TYPE_A; + } else + intelhaddata->curr_buf = buf_id + 1; + + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + + if (had_get_hwstate(intelhaddata)) { + pr_err("HDMI cable plugged-out\n"); + return 0; + } + + /*Reprogram the registers with addr and length*/ + had_write_register(intelhaddata, + AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), + buf_size); + had_write_register(intelhaddata, + AUD_BUF_A_ADDR + (buf_id * HAD_REG_WIDTH), + intelhaddata->buf_info[buf_id].buf_addr | + BIT(0) | BIT(1)); + + had_read_register(intelhaddata, + AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), + &len); + pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id); + + /* In case of actual data, + * report buffer_done to above ALSA layer + */ + buf_size = intelhaddata->buf_info[buf_id].buf_size; + if (stream_type >= HAD_RUNNING_STREAM) { + intelhaddata->stream_info.buffer_rendered += + (intr_count * buf_size); + stream->period_elapsed(stream->had_substream); + } + + return 0; +} + +static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) +{ + enum intel_had_aud_buf_type buf_id; + struct pcm_stream_info *stream; + struct had_stream_data *had_stream; + enum had_status_stream stream_type; + unsigned long flag_irqs; + int drv_status; + + had_stream = &intelhaddata->stream_data; + stream = &intelhaddata->stream_info; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + buf_id = intelhaddata->curr_buf; + stream_type = had_stream->stream_type; + intelhaddata->buff_done = buf_id; + drv_status = intelhaddata->drv_status; + if (stream_type == HAD_RUNNING_STREAM) + intelhaddata->curr_buf = HAD_BUF_TYPE_A; + + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + + pr_debug("Enter:%s buf_id=%d, stream_type=%d\n", + __func__, buf_id, stream_type); + + snd_intelhad_handle_underrun(intelhaddata); + + if (drv_status == HAD_DRV_DISCONNECTED) { + pr_err("%s:Device already disconnected\n", __func__); + return 0; + } + + if (stream_type == HAD_RUNNING_STREAM) { + /* Report UNDERRUN error to above layers */ + intelhaddata->flag_underrun = 1; + stream->period_elapsed(stream->had_substream); + } + + return 0; +} + +static int had_process_hot_plug(struct snd_intelhad *intelhaddata) +{ + enum intel_had_aud_buf_type buf_id; + struct snd_pcm_substream *substream; + struct had_stream_data *had_stream; + unsigned long flag_irqs; + + pr_debug("Enter:%s\n", __func__); + + substream = intelhaddata->stream_info.had_substream; + had_stream = &intelhaddata->stream_data; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { + pr_debug("Device already connected\n"); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + return 0; + } + buf_id = intelhaddata->curr_buf; + intelhaddata->buff_done = buf_id; + intelhaddata->drv_status = HAD_DRV_CONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", + __func__, __LINE__); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + + pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id); + + /* Safety check */ + if (substream) { + pr_debug("There should not be active PB from ALSA\n"); + pr_debug("Signifies, cable is plugged-in even before\n"); + pr_debug("processing snd_pcm_disconnect\n"); + /* Set runtime->state to hw_params done */ + snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + } + + had_build_channel_allocation_map(intelhaddata); + + return 0; +} + +static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) +{ + enum intel_had_aud_buf_type buf_id; + struct had_stream_data *had_stream; + unsigned long flag_irqs; + + pr_debug("Enter:%s\n", __func__); + + had_stream = &intelhaddata->stream_data; + buf_id = intelhaddata->curr_buf; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + pr_debug("Device already disconnected\n"); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + return 0; + + } else { + /* Disable Audio */ + snd_intelhad_enable_audio_int(intelhaddata, false); + snd_intelhad_enable_audio(intelhaddata, false); + } + + intelhaddata->drv_status = HAD_DRV_DISCONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + __func__, __LINE__); + + /* Report to above ALSA layer */ + if (intelhaddata->stream_info.had_substream != NULL) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__); + snd_pcm_stop(intelhaddata->stream_info.had_substream, + SNDRV_PCM_STATE_SETUP); + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + } + + had_stream->stream_type = HAD_INIT; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + kfree(intelhaddata->chmap->chmap); + intelhaddata->chmap->chmap = NULL; + intelhaddata->audio_reg_base = NULL; + pr_debug("%s: unlocked -> returned\n", __func__); + + return 0; +} + +/* PCM operations structure and the calls back for the same */ +static struct snd_pcm_ops snd_intelhad_playback_ops = { .open = snd_intelhad_open, .close = snd_intelhad_close, .ioctl = snd_pcm_lib_ioctl, @@ -1472,7 +1829,7 @@ struct snd_pcm_ops snd_intelhad_playback_ops = { .mmap = snd_intelhad_pcm_mmap, }; -/** +/* * snd_intelhad_pcm_free - to free the memory allocated * * @pcm: pointer to pcm instance @@ -1505,6 +1862,7 @@ static int had_iec958_get(struct snd_kcontrol *kcontrol, (intelhaddata->aes_bits >> 24) & 0xff; return 0; } + static int had_iec958_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1514,6 +1872,7 @@ static int had_iec958_mask_get(struct snd_kcontrol *kcontrol, ucontrol->value.iec958.status[3] = 0xff; return 0; } + static int had_iec958_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 6efa846f98c9..d301c3021375 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -154,35 +154,4 @@ struct snd_intelhad { struct work_struct hdmi_audio_wq; }; -int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state); -int hdmi_lpe_audio_resume(struct platform_device *pdev); -extern struct snd_pcm_ops snd_intelhad_playback_ops; - -int had_process_buffer_done(struct snd_intelhad *intelhaddata); -int had_process_buffer_underrun(struct snd_intelhad *intelhaddata); -int had_process_hot_plug(struct snd_intelhad *intelhaddata); -int had_process_hot_unplug(struct snd_intelhad *intelhaddata); - -int snd_intelhad_init_audio_ctrl(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata, - int flag_silence); -int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, - int start, int end); -int snd_intelhad_invd_buffer(int start, int end); -int snd_intelhad_read_len(struct snd_intelhad *intelhaddata); -void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata); - -void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable); -void snd_intelhad_enable_audio(struct snd_intelhad *ctx, bool enable); -void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata); - -/* Register access functions */ -int had_get_hwstate(struct snd_intelhad *intelhaddata); -int had_read_register(struct snd_intelhad *intelhaddata, - u32 reg_addr, u32 *data); -int had_write_register(struct snd_intelhad *intelhaddata, - u32 reg_addr, u32 data); -int had_read_modify(struct snd_intelhad *intelhaddata, - u32 reg_addr, u32 data, u32 mask); - #endif /* _INTEL_HDMI_AUDIO_ */ diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c deleted file mode 100644 index 327650dd1723..000000000000 --- a/sound/x86/intel_hdmi_audio_if.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * intel_hdmi_audio_if.c - Intel HDMI audio driver for MID - * - * Copyright (C) 2016 Intel Corp - * Authors: Sailaja Bandarupalli - * Ramesh Babu K V - * Vaibhav Agarwal - * Jerome Anand - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * ALSA driver for Intel MID HDMI audio controller. This file contains - * interface functions exposed to HDMI Display driver and code to register - * with ALSA framework.. - */ - -#define pr_fmt(fmt) "had: " fmt - -#include -#include -#include -#include -#include -#include "intel_hdmi_audio.h" -#include "intel_hdmi_lpe_audio.h" - -/* - * hdmi_lpe_audio_suspend - power management suspend function - * - * @pdev: platform device - * - * This function is called by client driver to suspend the - * hdmi audio. - */ -int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct had_stream_data *had_stream; - unsigned long flag_irqs; - struct snd_pcm_substream *substream; - struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - - pr_debug("Enter:%s\n", __func__); - - had_stream = &intelhaddata->stream_data; - substream = intelhaddata->stream_info.had_substream; - - if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { - pr_err("audio stream is active\n"); - return -EAGAIN; - } - - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had not connected\n"); - return 0; - } - - if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had already suspended\n"); - return 0; - } - - intelhaddata->drv_status = HAD_DRV_SUSPENDED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", - __func__, __LINE__); - - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - snd_intelhad_enable_audio_int(intelhaddata, false); - pr_debug("Exit:%s", __func__); - return 0; -} - -/* - * hdmi_lpe_audio_resume - power management resume function - * - *@pdev: platform device - * - * This function is called by client driver to resume the - * hdmi audio. - */ -int hdmi_lpe_audio_resume(struct platform_device *pdev) -{ - struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - unsigned long flag_irqs; - - pr_debug("Enter:%s\n", __func__); - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had not connected\n"); - return 0; - } - - if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("had is not in suspended state\n"); - return 0; - } - - if (had_get_hwstate(intelhaddata)) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("Failed to resume. Device not accessible\n"); - return -ENODEV; - } - - intelhaddata->drv_status = HAD_DRV_CONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", - __func__, __LINE__); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - snd_intelhad_enable_audio_int(intelhaddata, true); - pr_debug("Exit:%s", __func__); - return 0; -} - -static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, - enum intel_had_aud_buf_type buf_id) -{ - int i, intr_count = 0; - enum intel_had_aud_buf_type buff_done; - u32 buf_size, buf_addr; - struct had_stream_data *had_stream; - unsigned long flag_irqs; - - had_stream = &intelhaddata->stream_data; - - buff_done = buf_id; - - intr_count = snd_intelhad_read_len(intelhaddata); - if (intr_count > 1) { - /* In case of active playback */ - pr_err("Driver detected %d missed buffer done interrupt(s)!!!!\n", - (intr_count - 1)); - if (intr_count > 3) - return intr_count; - - buf_id += (intr_count - 1); - /* Reprogram registers*/ - for (i = buff_done; i < buf_id; i++) { - int j = i % 4; - - buf_size = intelhaddata->buf_info[j].buf_size; - buf_addr = intelhaddata->buf_info[j].buf_addr; - had_write_register(intelhaddata, - AUD_BUF_A_LENGTH + - (j * HAD_REG_WIDTH), buf_size); - had_write_register(intelhaddata, - AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH), - (buf_addr | BIT(0) | BIT(1))); - } - buf_id = buf_id % 4; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - intelhaddata->buff_done = buf_id; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - } - - return intr_count; -} - -int had_process_buffer_done(struct snd_intelhad *intelhaddata) -{ - u32 len = 1; - enum intel_had_aud_buf_type buf_id; - enum intel_had_aud_buf_type buff_done; - struct pcm_stream_info *stream; - u32 buf_size; - struct had_stream_data *had_stream; - int intr_count; - enum had_status_stream stream_type; - unsigned long flag_irqs; - - had_stream = &intelhaddata->stream_data; - stream = &intelhaddata->stream_info; - intr_count = 1; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("%s:Device already disconnected\n", __func__); - return 0; - } - buf_id = intelhaddata->curr_buf; - intelhaddata->buff_done = buf_id; - buff_done = intelhaddata->buff_done; - buf_size = intelhaddata->buf_info[buf_id].buf_size; - stream_type = had_stream->stream_type; - - pr_debug("Enter:%s buf_id=%d\n", __func__, buf_id); - - /* Every debug statement has an implication - * of ~5msec. Thus, avoid having >3 debug statements - * for each buffer_done handling. - */ - - /* Check for any intr_miss in case of active playback */ - if (had_stream->stream_type == HAD_RUNNING_STREAM) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - intr_count = had_chk_intrmiss(intelhaddata, buf_id); - if (!intr_count || (intr_count > 3)) { - pr_err("HAD SW state in non-recoverable!!! mode\n"); - pr_err("Already played stale data\n"); - return 0; - } - buf_id += (intr_count - 1); - buf_id = buf_id % 4; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - } - - intelhaddata->buf_info[buf_id].is_valid = true; - if (intelhaddata->valid_buf_cnt-1 == buf_id) { - if (had_stream->stream_type >= HAD_RUNNING_STREAM) - intelhaddata->curr_buf = HAD_BUF_TYPE_A; - } else - intelhaddata->curr_buf = buf_id + 1; - - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - - if (had_get_hwstate(intelhaddata)) { - pr_err("HDMI cable plugged-out\n"); - return 0; - } - - /*Reprogram the registers with addr and length*/ - had_write_register(intelhaddata, - AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), - buf_size); - had_write_register(intelhaddata, - AUD_BUF_A_ADDR + (buf_id * HAD_REG_WIDTH), - intelhaddata->buf_info[buf_id].buf_addr | - BIT(0) | BIT(1)); - - had_read_register(intelhaddata, - AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), - &len); - pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id); - - /* In case of actual data, - * report buffer_done to above ALSA layer - */ - buf_size = intelhaddata->buf_info[buf_id].buf_size; - if (stream_type >= HAD_RUNNING_STREAM) { - intelhaddata->stream_info.buffer_rendered += - (intr_count * buf_size); - stream->period_elapsed(stream->had_substream); - } - - return 0; -} - -int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) -{ - enum intel_had_aud_buf_type buf_id; - struct pcm_stream_info *stream; - struct had_stream_data *had_stream; - enum had_status_stream stream_type; - unsigned long flag_irqs; - int drv_status; - - had_stream = &intelhaddata->stream_data; - stream = &intelhaddata->stream_info; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - buf_id = intelhaddata->curr_buf; - stream_type = had_stream->stream_type; - intelhaddata->buff_done = buf_id; - drv_status = intelhaddata->drv_status; - if (stream_type == HAD_RUNNING_STREAM) - intelhaddata->curr_buf = HAD_BUF_TYPE_A; - - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - - pr_debug("Enter:%s buf_id=%d, stream_type=%d\n", - __func__, buf_id, stream_type); - - snd_intelhad_handle_underrun(intelhaddata); - - if (drv_status == HAD_DRV_DISCONNECTED) { - pr_err("%s:Device already disconnected\n", __func__); - return 0; - } - - if (stream_type == HAD_RUNNING_STREAM) { - /* Report UNDERRUN error to above layers */ - intelhaddata->flag_underrun = 1; - stream->period_elapsed(stream->had_substream); - } - - return 0; -} - -int had_process_hot_plug(struct snd_intelhad *intelhaddata) -{ - enum intel_had_aud_buf_type buf_id; - struct snd_pcm_substream *substream; - struct had_stream_data *had_stream; - unsigned long flag_irqs; - - pr_debug("Enter:%s\n", __func__); - - substream = intelhaddata->stream_info.had_substream; - had_stream = &intelhaddata->stream_data; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { - pr_debug("Device already connected\n"); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - return 0; - } - buf_id = intelhaddata->curr_buf; - intelhaddata->buff_done = buf_id; - intelhaddata->drv_status = HAD_DRV_CONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", - __func__, __LINE__); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - - pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id); - - /* Safety check */ - if (substream) { - pr_debug("There should not be active PB from ALSA\n"); - pr_debug("Signifies, cable is plugged-in even before\n"); - pr_debug("processing snd_pcm_disconnect\n"); - /* Set runtime->state to hw_params done */ - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - } - - had_build_channel_allocation_map(intelhaddata); - - return 0; -} - -int had_process_hot_unplug(struct snd_intelhad *intelhaddata) -{ - enum intel_had_aud_buf_type buf_id; - struct had_stream_data *had_stream; - unsigned long flag_irqs; - - pr_debug("Enter:%s\n", __func__); - - had_stream = &intelhaddata->stream_data; - buf_id = intelhaddata->curr_buf; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - pr_debug("Device already disconnected\n"); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - return 0; - - } else { - /* Disable Audio */ - snd_intelhad_enable_audio_int(intelhaddata, false); - snd_intelhad_enable_audio(intelhaddata, false); - } - - intelhaddata->drv_status = HAD_DRV_DISCONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", - __func__, __LINE__); - - /* Report to above ALSA layer */ - if (intelhaddata->stream_info.had_substream != NULL) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__); - snd_pcm_stop(intelhaddata->stream_info.had_substream, - SNDRV_PCM_STATE_SETUP); - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - } - - had_stream->stream_type = HAD_INIT; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - kfree(intelhaddata->chmap->chmap); - intelhaddata->chmap->chmap = NULL; - intelhaddata->audio_reg_base = NULL; - pr_debug("%s: unlocked -> returned\n", __func__); - - return 0; -} - From c75b0476245ad01306e4ea510bb3f7591767079f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 15:49:15 +0100 Subject: [PATCH 27/54] ALSA: x86: Replace pr_xxx() with dev_xxx() dev_xxx() helpers give a tidier output in general. While we're at it, remove many useless debug prints (e.g. the ones at each function entry), replace some too verbose errors with debugs, and use WARN_ON() for some serious errors. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 205 ++++++++++++++--------------------- 1 file changed, 84 insertions(+), 121 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index effe93b58273..41105092c114 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -21,8 +21,6 @@ * ALSA driver for Intel HDMI audio */ -#define pr_fmt(fmt) "had: " fmt - #include #include #include @@ -160,11 +158,8 @@ static const struct snd_pcm_hardware snd_intel_hadstream = { static int had_get_hwstate(struct snd_intelhad *intelhaddata) { /* Check for device presence -SW state */ - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - pr_debug("%s:Device not connected:%d\n", __func__, - intelhaddata->drv_status); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) return -ENODEV; - } return 0; } @@ -276,7 +271,8 @@ static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata, data = data | cfg_val.cfg_regval; mask = mask | AUD_CONFIG_CH_MASK_V2; - pr_debug("%s : data = %x, mask =%x\n", __func__, data, mask); + dev_dbg(intelhaddata->dev, "%s : data = %x, mask =%x\n", + __func__, data, mask); return had_read_modify(intelhaddata, AUD_CONFIG, data, mask); } @@ -318,8 +314,6 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0}; int format; - pr_debug("Entry %s\n", __func__); - ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits & IEC958_AES0_NONAUDIO)>>1; ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & @@ -415,8 +409,6 @@ static void init_channel_allocations(void) int i, j; struct cea_channel_speaker_allocation *p; - pr_debug("%s: Enter\n", __func__); - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { p = channel_allocations + i; p->channels = 0; @@ -472,7 +464,7 @@ static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata, } } - pr_debug("HDMI: select CA 0x%x for %d\n", ca, channels); + dev_dbg(intelhaddata->dev, "select CA 0x%x for %d\n", ca, channels); return ca; } @@ -503,7 +495,7 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) return; } - pr_debug("eld.speaker_allocation_block = %x\n", + dev_dbg(intelhaddata->dev, "eld.speaker_allocation_block = %x\n", intelhaddata->eld.speaker_allocation_block); /* WA: Fix the max channel supported to 8 */ @@ -583,10 +575,8 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, if (intelhaddata->chmap->chmap == NULL) return -ENODATA; chmap = intelhaddata->chmap->chmap; - for (i = 0; i < chmap->channels; i++) { + for (i = 0; i < chmap->channels; i++) ucontrol->value.integer.value[i] = chmap->map[i]; - pr_debug("chmap->map[%d] = %d\n", i, chmap->map[i]); - } return 0; } @@ -684,11 +674,8 @@ static int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, struct snd_pcm_substream *substream; substream = intelhaddata->stream_info.had_substream; - if (!substream) { - pr_err("substream is NULL\n"); - dump_stack(); + if (WARN_ON(!substream)) return 0; - } ring_buf_addr = substream->runtime->dma_addr; ring_buf_size = snd_pcm_lib_buffer_bytes(substream); @@ -726,9 +713,10 @@ static int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, period_bytes); intelhaddata->buf_info[i].is_valid = true; } - pr_debug("%s:buf[%d-%d] addr=%#x and size=%d\n", __func__, start, end, - intelhaddata->buf_info[start].buf_addr, - intelhaddata->buf_info[start].buf_size); + dev_dbg(intelhaddata->dev, "%s:buf[%d-%d] addr=%#x and size=%d\n", + __func__, start, end, + intelhaddata->buf_info[start].buf_addr, + intelhaddata->buf_info[start].buf_size); intelhaddata->valid_buf_cnt = num_periods; return 0; } @@ -747,7 +735,8 @@ static int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) } if (retval != 1) { for (i = 0; i < 4 ; i++) - pr_debug("buf[%d] size=%d\n", i, len[i]); + dev_dbg(intelhaddata->dev, "buf[%d] size=%d\n", + i, len[i]); } return retval; @@ -858,7 +847,7 @@ static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, divisor = 128 * aud_samp_freq; cts_val = div64_u64(dividend, divisor); } - pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n", + dev_dbg(intelhaddata->dev, "TMDS value=%d, N value=%d, CTS Value=%d\n", tmds, n_param, cts_val); had_write_register(intelhaddata, AUD_HDMI_CTS, (BIT(24) | cts_val)); } @@ -956,7 +945,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) do { /* clear bit30, 31 AUD_HDMI_STATUS */ had_read_register(intelhaddata, AUD_HDMI_STATUS_v2, &hdmi_status); - pr_debug("HDMI status =0x%x\n", hdmi_status); + dev_dbg(intelhaddata->dev, "HDMI status =0x%x\n", hdmi_status); if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { i++; had_write_register(intelhaddata, @@ -965,7 +954,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) break; } while (i < MAX_CNT); if (i >= MAX_CNT) - pr_err("Unable to clear UNDERRUN bits\n"); + dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n"); } /** @@ -982,7 +971,6 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) struct had_stream_data *had_stream; int retval; - pr_debug("snd_intelhad_open called\n"); intelhaddata = snd_pcm_substream_chip(substream); had_stream = &intelhaddata->stream_data; runtime = substream->runtime; @@ -991,14 +979,15 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) pm_runtime_get(intelhaddata->dev); if (had_get_hwstate(intelhaddata)) { - pr_err("%s: HDMI cable plugged-out\n", __func__); + dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", + __func__); retval = -ENODEV; goto exit_put_handle; } /* Check, if device already in use */ if (runtime->private_data) { - pr_err("Device already in use\n"); + dev_dbg(intelhaddata->dev, "Device already in use\n"); retval = -EBUSY; goto exit_put_handle; } @@ -1025,7 +1014,8 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) retval = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); if (retval < 0) { - pr_err("%s:step_size=64 failed,err=%d\n", __func__, retval); + dev_dbg(intelhaddata->dev, "%s:step_size=64 failed,err=%d\n", + __func__, retval); goto exit_err; } @@ -1048,8 +1038,6 @@ static void had_period_elapsed(void *had_substream) struct snd_pcm_substream *substream = had_substream; struct had_stream_pvt *stream; - /* pr_debug("had_period_elapsed called\n"); */ - if (!substream || !substream->runtime) return; stream = substream->runtime->private_data; @@ -1070,9 +1058,6 @@ static int snd_intelhad_init_stream(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); - pr_debug("snd_intelhad_init_stream called\n"); - - pr_debug("setting buffer ptr param\n"); intelhaddata->stream_info.period_elapsed = had_period_elapsed; intelhaddata->stream_info.had_substream = substream; intelhaddata->stream_info.buffer_ptr = 0; @@ -1093,15 +1078,11 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; - pr_debug("snd_intelhad_close called\n"); - intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - if (!runtime->private_data) { - pr_debug("close() might have called after failed open"); + if (WARN_ON(!runtime->private_data)) return 0; - } intelhaddata->stream_info.buffer_rendered = 0; intelhaddata->stream_info.buffer_ptr = 0; @@ -1111,7 +1092,8 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) /* Check if following drv_status modification is required - VA */ if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { intelhaddata->drv_status = HAD_DRV_CONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); } kfree(runtime->private_data); @@ -1132,25 +1114,27 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { + struct snd_intelhad *intelhaddata; unsigned long addr; int pages, buf_size, retval; - pr_debug("snd_intelhad_hw_params called\n"); - if (!hw_params) return -EINVAL; + intelhaddata = snd_pcm_substream_chip(substream); buf_size = params_buffer_bytes(hw_params); retval = snd_pcm_lib_malloc_pages(substream, buf_size); if (retval < 0) return retval; - pr_debug("%s:allocated memory = %d\n", __func__, buf_size); + dev_dbg(intelhaddata->dev, "%s:allocated memory = %d\n", + __func__, buf_size); /* mark the pages as uncached region */ addr = (unsigned long) substream->runtime->dma_area; pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE; retval = set_memory_uc(addr, pages); if (retval) { - pr_err("set_memory_uc failed.Error:%d\n", retval); + dev_err(intelhaddata->dev, "set_memory_uc failed.Error:%d\n", + retval); return retval; } memset(substream->runtime->dma_area, 0, buf_size); @@ -1172,8 +1156,6 @@ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) unsigned long addr; u32 pages; - pr_debug("snd_intelhad_hw_free called\n"); - /* mark back the pages as cached/writeback region before the free */ if (substream->runtime->dma_area != NULL) { addr = (unsigned long) substream->runtime->dma_area; @@ -1200,19 +1182,16 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, struct had_stream_pvt *stream; struct had_stream_data *had_stream; - pr_debug("snd_intelhad_pcm_trigger called\n"); - intelhaddata = snd_pcm_substream_chip(substream); stream = substream->runtime->private_data; had_stream = &intelhaddata->stream_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - pr_debug("Trigger Start\n"); - /* Disable local INTRs till register prgmng is done */ if (had_get_hwstate(intelhaddata)) { - pr_err("_START: HDMI cable plugged-out\n"); + dev_dbg(intelhaddata->dev, + "_START: HDMI cable plugged-out\n"); retval = -ENODEV; break; } @@ -1223,18 +1202,14 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, /* Enable Audio */ snd_intelhad_enable_audio_int(intelhaddata, true); snd_intelhad_enable_audio(intelhaddata, true); - - pr_debug("Processed _Start\n"); - break; case SNDRV_PCM_TRIGGER_STOP: - pr_debug("Trigger Stop\n"); spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irq); intelhaddata->stream_info.str_id = 0; intelhaddata->curr_buf = 0; - /* Stop reporting BUFFER_DONE/UNDERRUN to above layers*/ + /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ had_stream->stream_type = HAD_INIT; spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq); @@ -1270,27 +1245,28 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime; struct had_stream_data *had_stream; - pr_debug("snd_intelhad_pcm_prepare called\n"); - intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; had_stream = &intelhaddata->stream_data; if (had_get_hwstate(intelhaddata)) { - pr_err("%s: HDMI cable plugged-out\n", __func__); + dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", + __func__); retval = -ENODEV; goto prep_end; } - pr_debug("period_size=%d\n", + dev_dbg(intelhaddata->dev, "period_size=%d\n", (int)frames_to_bytes(runtime, runtime->period_size)); - pr_debug("periods=%d\n", runtime->periods); - pr_debug("buffer_size=%d\n", (int)snd_pcm_lib_buffer_bytes(substream)); - pr_debug("rate=%d\n", runtime->rate); - pr_debug("channels=%d\n", runtime->channels); + dev_dbg(intelhaddata->dev, "periods=%d\n", runtime->periods); + dev_dbg(intelhaddata->dev, "buffer_size=%d\n", + (int)snd_pcm_lib_buffer_bytes(substream)); + dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate); + dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels); if (intelhaddata->stream_info.str_id) { - pr_debug("_prepare is called for existing str_id#%d\n", + dev_dbg(intelhaddata->dev, + "_prepare is called for existing str_id#%d\n", intelhaddata->stream_info.str_id); retval = snd_intelhad_pcm_trigger(substream, SNDRV_PCM_TRIGGER_STOP); @@ -1308,7 +1284,8 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, intelhaddata); if (retval) { - pr_err("programming N value failed %#x\n", retval); + dev_err(intelhaddata->dev, + "programming N value failed %#x\n", retval); goto prep_end; } @@ -1354,8 +1331,6 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( u32 t; int buf_id; - /* pr_debug("snd_intelhad_pcm_pointer called\n"); */ - intelhaddata = snd_pcm_substream_chip(substream); if (intelhaddata->flag_underrun) { @@ -1373,11 +1348,13 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( if ((t == 0) || (t == ((u32)-1L))) { intelhaddata->underrun_count++; - pr_debug("discovered buffer done for buf %d, count = %d\n", + dev_dbg(intelhaddata->dev, + "discovered buffer done for buf %d, count = %d\n", buf_id, intelhaddata->underrun_count); if (intelhaddata->underrun_count > (HAD_MIN_PERIODS/2)) { - pr_debug("assume audio_codec_reset, underrun = %d - do xrun\n", + dev_dbg(intelhaddata->dev, + "assume audio_codec_reset, underrun = %d - do xrun\n", intelhaddata->underrun_count); intelhaddata->underrun_count = 0; return SNDRV_PCM_POS_XRUN; @@ -1412,10 +1389,6 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { - - pr_debug("snd_intelhad_pcm_mmap called\n"); - - pr_debug("entry with prot:%s\n", __func__); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); return remap_pfn_range(vma, vma->vm_start, substream->dma_buffer.addr >> PAGE_SHIFT, @@ -1442,7 +1415,8 @@ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, intelhaddata); if (retval) { - pr_err("programming N value failed %#x\n", retval); + dev_err(intelhaddata->dev, + "programming N value failed %#x\n", retval); goto out; } @@ -1476,13 +1450,11 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, struct snd_pcm_substream *substream; struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - pr_debug("Enter:%s\n", __func__); - had_stream = &intelhaddata->stream_data; substream = intelhaddata->stream_info.had_substream; if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { - pr_err("audio stream is active\n"); + dev_err(intelhaddata->dev, "audio stream is active\n"); return -EAGAIN; } @@ -1490,23 +1462,23 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had not connected\n"); + dev_dbg(intelhaddata->dev, "had not connected\n"); return 0; } if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had already suspended\n"); + dev_dbg(intelhaddata->dev, "had already suspended\n"); return 0; } intelhaddata->drv_status = HAD_DRV_SUSPENDED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", __func__, __LINE__); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); snd_intelhad_enable_audio_int(intelhaddata, false); - pr_debug("Exit:%s", __func__); return 0; } @@ -1523,33 +1495,32 @@ static int hdmi_lpe_audio_resume(struct platform_device *pdev) struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); unsigned long flag_irqs; - pr_debug("Enter:%s\n", __func__); - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had not connected\n"); + dev_dbg(intelhaddata->dev, "had not connected\n"); return 0; } if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("had is not in suspended state\n"); + dev_err(intelhaddata->dev, "had is not in suspended state\n"); return 0; } if (had_get_hwstate(intelhaddata)) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("Failed to resume. Device not accessible\n"); + dev_err(intelhaddata->dev, + "Failed to resume. Device not accessible\n"); return -ENODEV; } intelhaddata->drv_status = HAD_DRV_CONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); snd_intelhad_enable_audio_int(intelhaddata, true); - pr_debug("Exit:%s", __func__); return 0; } @@ -1569,8 +1540,9 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, intr_count = snd_intelhad_read_len(intelhaddata); if (intr_count > 1) { /* In case of active playback */ - pr_err("Driver detected %d missed buffer done interrupt(s)!!!!\n", - (intr_count - 1)); + dev_err(intelhaddata->dev, + "Driver detected %d missed buffer done interrupt(s)\n", + (intr_count - 1)); if (intr_count > 3) return intr_count; @@ -1616,7 +1588,8 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("%s:Device already disconnected\n", __func__); + dev_dbg(intelhaddata->dev, + "%s:Device already disconnected\n", __func__); return 0; } buf_id = intelhaddata->curr_buf; @@ -1625,8 +1598,6 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) buf_size = intelhaddata->buf_info[buf_id].buf_size; stream_type = had_stream->stream_type; - pr_debug("Enter:%s buf_id=%d\n", __func__, buf_id); - /* Every debug statement has an implication * of ~5msec. Thus, avoid having >3 debug statements * for each buffer_done handling. @@ -1637,8 +1608,8 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); intr_count = had_chk_intrmiss(intelhaddata, buf_id); if (!intr_count || (intr_count > 3)) { - pr_err("HAD SW state in non-recoverable!!! mode\n"); - pr_err("Already played stale data\n"); + dev_err(intelhaddata->dev, + "HAD SW state in non-recoverable mode\n"); return 0; } buf_id += (intr_count - 1); @@ -1656,7 +1627,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); if (had_get_hwstate(intelhaddata)) { - pr_err("HDMI cable plugged-out\n"); + dev_dbg(intelhaddata->dev, "HDMI cable plugged-out\n"); return 0; } @@ -1672,7 +1643,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) had_read_register(intelhaddata, AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &len); - pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id); + dev_dbg(intelhaddata->dev, "%s:Enabled buf[%d]\n", __func__, buf_id); /* In case of actual data, * report buffer_done to above ALSA layer @@ -1709,13 +1680,14 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("Enter:%s buf_id=%d, stream_type=%d\n", + dev_dbg(intelhaddata->dev, "Enter:%s buf_id=%d, stream_type=%d\n", __func__, buf_id, stream_type); snd_intelhad_handle_underrun(intelhaddata); if (drv_status == HAD_DRV_DISCONNECTED) { - pr_err("%s:Device already disconnected\n", __func__); + dev_dbg(intelhaddata->dev, + "%s:Device already disconnected\n", __func__); return 0; } @@ -1735,31 +1707,30 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) struct had_stream_data *had_stream; unsigned long flag_irqs; - pr_debug("Enter:%s\n", __func__); - substream = intelhaddata->stream_info.had_substream; had_stream = &intelhaddata->stream_data; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { - pr_debug("Device already connected\n"); + dev_dbg(intelhaddata->dev, "Device already connected\n"); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); return 0; } buf_id = intelhaddata->curr_buf; intelhaddata->buff_done = buf_id; intelhaddata->drv_status = HAD_DRV_CONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id); + dev_dbg(intelhaddata->dev, "Processing HOT_PLUG, buf_id = %d\n", + buf_id); /* Safety check */ if (substream) { - pr_debug("There should not be active PB from ALSA\n"); - pr_debug("Signifies, cable is plugged-in even before\n"); - pr_debug("processing snd_pcm_disconnect\n"); + dev_dbg(intelhaddata->dev, + "Force to stop the active stream by disconnection\n"); /* Set runtime->state to hw_params done */ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); } @@ -1775,15 +1746,13 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) struct had_stream_data *had_stream; unsigned long flag_irqs; - pr_debug("Enter:%s\n", __func__); - had_stream = &intelhaddata->stream_data; buf_id = intelhaddata->curr_buf; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - pr_debug("Device already disconnected\n"); + dev_dbg(intelhaddata->dev, "Device already disconnected\n"); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); return 0; @@ -1794,13 +1763,13 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) } intelhaddata->drv_status = HAD_DRV_DISCONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); /* Report to above ALSA layer */ if (intelhaddata->stream_info.had_substream != NULL) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__); snd_pcm_stop(intelhaddata->stream_info.had_substream, SNDRV_PCM_STATE_SETUP); spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); @@ -1811,7 +1780,6 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; intelhaddata->audio_reg_base = NULL; - pr_debug("%s: unlocked -> returned\n", __func__); return 0; } @@ -1837,7 +1805,6 @@ static struct snd_pcm_ops snd_intelhad_playback_ops = { */ static void snd_intelhad_pcm_free(struct snd_pcm *pcm) { - pr_debug("Freeing PCM preallocated pages\n"); snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1879,7 +1846,6 @@ static int had_iec958_put(struct snd_kcontrol *kcontrol, unsigned int val; struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); - pr_debug("entered had_iec958_put\n"); val = (ucontrol->value.iec958.status[0] << 0) | (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | @@ -2024,7 +1990,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) int ret; unsigned long flags; - dev_dbg(&pdev->dev, "Enter %s\n", __func__); dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); pdata = pdev->dev.platform_data; @@ -2170,8 +2135,6 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { struct snd_intelhad *ctx = platform_get_drvdata(pdev); - dev_dbg(&pdev->dev, "Enter %s\n", __func__); - if (ctx->drv_status != HAD_DRV_DISCONNECTED) snd_intelhad_enable_audio_int(ctx, false); snd_card_free(ctx->card); From e29c0f967261b0f6a95e05a224341be8f59df2d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 17:27:48 +0100 Subject: [PATCH 28/54] ALSA: x86: Fix for CONFIG_PM=n The direct access to power.runtime_status is taboo, let's use a helper macro to avoid the compile error with CONFIG_PM=n. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 41105092c114..fbfbf5e2b5ad 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1453,7 +1453,7 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, had_stream = &intelhaddata->stream_data; substream = intelhaddata->stream_info.had_substream; - if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { + if (!pm_runtime_status_suspended(intelhaddata->dev)) { dev_err(intelhaddata->dev, "audio stream is active\n"); return -EAGAIN; } From df76df12f178642cac616b86a762d2ee749fe402 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:04:10 +0100 Subject: [PATCH 29/54] ALSA: x86: Remove indirect call of snd_pcm_period_elapsed() Again another indirect call... Let's straighten it up. Also define the had_stream field with a proper type instead of a void pointer. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 15 ++++++--------- sound/x86/intel_hdmi_audio.h | 3 +-- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index fbfbf5e2b5ad..8b25687601ac 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1028,14 +1028,12 @@ exit_put_handle: return retval; } -/** +/* * had_period_elapsed - updates the hardware pointer status - * @had_substream:substream for which the stream function is called - * + * @had_substream: substream for which the stream function is called */ -static void had_period_elapsed(void *had_substream) +static void had_period_elapsed(struct snd_pcm_substream *substream) { - struct snd_pcm_substream *substream = had_substream; struct had_stream_pvt *stream; if (!substream || !substream->runtime) @@ -1058,7 +1056,6 @@ static int snd_intelhad_init_stream(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); - intelhaddata->stream_info.period_elapsed = had_period_elapsed; intelhaddata->stream_info.had_substream = substream; intelhaddata->stream_info.buffer_ptr = 0; intelhaddata->stream_info.buffer_rendered = 0; @@ -1648,11 +1645,11 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) /* In case of actual data, * report buffer_done to above ALSA layer */ - buf_size = intelhaddata->buf_info[buf_id].buf_size; + buf_size = intelhaddata->buf_info[buf_id].buf_size; if (stream_type >= HAD_RUNNING_STREAM) { intelhaddata->stream_info.buffer_rendered += (intr_count * buf_size); - stream->period_elapsed(stream->had_substream); + had_period_elapsed(stream->had_substream); } return 0; @@ -1694,7 +1691,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (stream_type == HAD_RUNNING_STREAM) { /* Report UNDERRUN error to above layers */ intelhaddata->flag_underrun = 1; - stream->period_elapsed(stream->had_substream); + had_period_elapsed(stream->had_substream); } return 0; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index d301c3021375..bcbb4b262fff 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -75,8 +75,7 @@ struct platform_device; struct pcm_stream_info { int str_id; - void *had_substream; - void (*period_elapsed)(void *had_substream); + struct snd_pcm_substream *had_substream; u32 buffer_ptr; u64 buffer_rendered; u32 ring_buf_size; From e9d65abfa63fad3da372a3852dcade88b5506f4c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:11:27 +0100 Subject: [PATCH 30/54] ALSA: x86: Drop unused fields from snd_intelhad struct Also change the flag_underrun to bool to be clearer. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 14 +++++--------- sound/x86/intel_hdmi_audio.h | 14 +------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 8b25687601ac..0a14f5dacb00 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -593,9 +593,8 @@ static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, return err; intelhaddata->chmap->private_data = intelhaddata; - intelhaddata->kctl = intelhaddata->chmap->kctl; - intelhaddata->kctl->info = had_chmap_ctl_info; - intelhaddata->kctl->get = had_chmap_ctl_get; + intelhaddata->chmap->kctl->info = had_chmap_ctl_info; + intelhaddata->chmap->kctl->get = had_chmap_ctl_get; intelhaddata->chmap->chmap = NULL; return 0; } @@ -1331,7 +1330,7 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( intelhaddata = snd_pcm_substream_chip(substream); if (intelhaddata->flag_underrun) { - intelhaddata->flag_underrun = 0; + intelhaddata->flag_underrun = false; return SNDRV_PCM_POS_XRUN; } @@ -1690,7 +1689,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (stream_type == HAD_RUNNING_STREAM) { /* Report UNDERRUN error to above layers */ - intelhaddata->flag_underrun = 1; + intelhaddata->flag_underrun = true; had_period_elapsed(stream->had_substream); } @@ -1776,7 +1775,6 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; - intelhaddata->audio_reg_base = NULL; return 0; } @@ -2019,9 +2017,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->drv_status = HAD_DRV_DISCONNECTED; ctx->dev = &pdev->dev; ctx->card = card; - ctx->card_id = hdmi_card_id; - ctx->card_index = card->number; - ctx->flag_underrun = 0; + ctx->flag_underrun = false; ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; strcpy(card->driver, INTEL_HAD); strcpy(card->shortname, INTEL_HAD); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index bcbb4b262fff..4549c4d9d650 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -39,8 +39,6 @@ #include #include "intel_hdmi_lpe_audio.h" -struct platform_device; - #define PCM_INDEX 0 #define MAX_PB_STREAMS 1 #define MAX_CAP_STREAMS 0 @@ -102,8 +100,6 @@ struct had_stream_data { * struct snd_intelhad - intelhad driver structure * * @card: ptr to hold card details - * @card_index: sound card index - * @card_id: detected sound card id * @drv_status: driver status * @buf_info: ring buffer info * @stream_info: stream information @@ -114,15 +110,11 @@ struct had_stream_data { * @aes_bits: IEC958 status bits * @buff_done: id of current buffer done intr * @dev: platoform device handle - * @kctl: holds kctl ptrs used for channel map * @chmap: holds channel map info - * @audio_reg_base: hdmi audio register base offset * @underrun_count: PCM stream underrun counter */ struct snd_intelhad { struct snd_card *card; - int card_index; - char *card_id; enum had_drv_status drv_status; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; @@ -131,15 +123,12 @@ struct snd_intelhad { enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; unsigned int aes_bits; - int flag_underrun; + bool flag_underrun; struct had_stream_data stream_data; spinlock_t had_spinlock; enum intel_had_aud_buf_type buff_done; struct device *dev; - struct snd_kcontrol *kctl; struct snd_pcm_chmap *chmap; - unsigned int *audio_reg_base; - unsigned int audio_cfg_offset; int underrun_count; enum hdmi_connector_status state; int tmds_clock_speed; @@ -149,7 +138,6 @@ struct snd_intelhad { int irq; void __iomem *mmio_start; unsigned int had_config_offset; - int hdmi_audio_interrupt_mask; struct work_struct hdmi_audio_wq; }; From f6a82a0c01e51dd494b6eb68861473368355e58b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:17:14 +0100 Subject: [PATCH 31/54] ALSA: x86: Drop superfluous PCM private_free snd_pcm_lib_preallocate_free_for_all() doesn't have to be called from each driver as it's called in the PCM core. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 0a14f5dacb00..28eb980d2d2e 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1792,17 +1792,6 @@ static struct snd_pcm_ops snd_intelhad_playback_ops = { .mmap = snd_intelhad_pcm_mmap, }; -/* - * snd_intelhad_pcm_free - to free the memory allocated - * - * @pcm: pointer to pcm instance - * This function is called when the device is removed - */ -static void snd_intelhad_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int had_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -2063,7 +2052,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) /* setup private data which can be retrieved when required */ pcm->private_data = ctx; - pcm->private_free = snd_intelhad_pcm_free; pcm->info_flags = 0; strncpy(pcm->name, card->shortname, strlen(card->shortname)); /* setup the ops for playabck */ From 99b2ab9d3aa08824dfefd7d9ad9f2b4c19555d05 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:26:10 +0100 Subject: [PATCH 32/54] ALSA: x86: Fix sleep-in-atomic via i915 notification i915 notification is executed in a spinlock, thus it must not sleep; i.e. we can't use kmalloc with GFP_KERNEL or such. For making it working properly, move the notification handler in a work, and handle it gracefully. We have already such a work, and it was used just at the start. This can be re-used in a more generic hotplug handling. Also, the patch adds the proper call of cancel_work_sync() to the destructor. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 51 +++++++++++++++++------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 28eb980d2d2e..ab199b5deaa5 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1857,14 +1857,6 @@ static struct snd_kcontrol_new had_control_iec958 = { .put = had_iec958_put }; -static void _had_wq(struct work_struct *work) -{ - struct snd_intelhad *ctx = - container_of(work, struct snd_intelhad, hdmi_audio_wq); - - had_process_hot_plug(ctx); -} - static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { struct snd_intelhad *ctx = dev_id; @@ -1889,21 +1881,28 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) static void notify_audio_lpe(struct platform_device *pdev) { struct snd_intelhad *ctx = platform_get_drvdata(pdev); - struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data; - if (pdata->hdmi_connected != true) { + schedule_work(&ctx->hdmi_audio_wq); +} - dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", +static void had_audio_wq(struct work_struct *work) +{ + struct snd_intelhad *ctx = + container_of(work, struct snd_intelhad, hdmi_audio_wq); + struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data; + + if (!pdata->hdmi_connected) { + dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", __func__); - if (ctx->state == hdmi_connector_status_connected) { - - ctx->state = hdmi_connector_status_disconnected; - - had_process_hot_unplug(ctx); - } else - dev_dbg(&pdev->dev, "%s: Already Unplugged!\n", + if (ctx->state != hdmi_connector_status_connected) { + dev_dbg(ctx->dev, "%s: Already Unplugged!\n", __func__); + return; + } + + ctx->state = hdmi_connector_status_disconnected; + had_process_hot_unplug(ctx); } else { struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; @@ -1919,7 +1918,7 @@ static void notify_audio_lpe(struct platform_device *pdev) ctx->had_config_offset = AUDIO_HDMI_CONFIG_C; break; default: - dev_dbg(&pdev->dev, "Invalid pipe %d\n", + dev_dbg(ctx->dev, "Invalid pipe %d\n", eld->pipe_id); break; } @@ -1930,7 +1929,7 @@ static void notify_audio_lpe(struct platform_device *pdev) ctx->state = hdmi_connector_status_connected; - dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", + dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", __func__, eld->port_id, pdata->tmds_clock_speed); if (pdata->tmds_clock_speed) { @@ -1950,6 +1949,8 @@ static void hdmi_lpe_audio_free(struct snd_card *card) { struct snd_intelhad *ctx = card->private_data; + cancel_work_sync(&ctx->hdmi_audio_wq); + if (ctx->mmio_start) iounmap(ctx->mmio_start); if (ctx->irq >= 0) @@ -2013,7 +2014,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->irq = -1; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; - INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); + INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq); ctx->state = hdmi_connector_status_disconnected; card->private_free = hdmi_lpe_audio_free; @@ -2086,17 +2087,13 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) spin_lock_irqsave(&pdata->lpe_audio_slock, flags); pdata->notify_audio_lpe = notify_audio_lpe; - if (pdata->notify_pending) { - - dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); - notify_audio_lpe(pdev); - pdata->notify_pending = false; - } + pdata->notify_pending = false; spin_unlock_irqrestore(&pdata->lpe_audio_slock, flags); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); schedule_work(&ctx->hdmi_audio_wq); return 0; From caa2a61a702a2a391b2fb695fc245ca5b8a4ffd8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:38:22 +0100 Subject: [PATCH 33/54] ALSA: x86: Remove superfluous check at resume The had_get_hwstate() is identical with drv_status==DISCONECTED, which was already checked before the call. And, returning an error at resume is simply bad. That is, we should just kill this check. Also, spewing an error at resume for drv_status!=SUSPENDED is also annoying, as this is the normal case when the suspend was called without the monitor connection. Make it debug, too. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index ab199b5deaa5..835e0f2c4f0b 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1454,7 +1454,6 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, return -EAGAIN; } - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); @@ -1500,17 +1499,10 @@ static int hdmi_lpe_audio_resume(struct platform_device *pdev) if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - dev_err(intelhaddata->dev, "had is not in suspended state\n"); + dev_dbg(intelhaddata->dev, "had is not in suspended state\n"); return 0; } - if (had_get_hwstate(intelhaddata)) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - dev_err(intelhaddata->dev, - "Failed to resume. Device not accessible\n"); - return -ENODEV; - } - intelhaddata->drv_status = HAD_DRV_CONNECTED; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", From 79f439ea4007b94beeb8ba1e00e71f9d128b0f90 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:46:44 +0100 Subject: [PATCH 34/54] ALSA: x86: Drop had_get_hwstate() The helper function isn't clearer than the plain condition check "if (drv_status == HDA_DRV_DISCONNECTED)". By expanding this, the compiler could even catch the possible uninitialized cases, so we could fix them, too. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 42 ++++++++++++------------------------ 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 835e0f2c4f0b..7c6549a10c1c 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -155,15 +155,6 @@ static const struct snd_pcm_hardware snd_intel_hadstream = { }; /* Register access functions */ -static int had_get_hwstate(struct snd_intelhad *intelhaddata) -{ - /* Check for device presence -SW state */ - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) - return -ENODEV; - - return 0; -} - static inline void mid_hdmi_audio_read(struct snd_intelhad *ctx, u32 reg, u32 *val) { @@ -179,11 +170,8 @@ mid_hdmi_audio_write(struct snd_intelhad *ctx, u32 reg, u32 val) static int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) { - int retval; - - retval = had_get_hwstate(intelhaddata); - if (retval) - return retval; + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + return -ENODEV; mid_hdmi_audio_read(intelhaddata, offset, data); return 0; @@ -201,11 +189,8 @@ static void fixup_dp_config(struct snd_intelhad *intelhaddata, static int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) { - int retval; - - retval = had_get_hwstate(intelhaddata); - if (retval) - return retval; + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + return -ENODEV; fixup_dp_config(intelhaddata, offset, &data); mid_hdmi_audio_write(intelhaddata, offset, data); @@ -216,11 +201,9 @@ static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, u32 data, u32 mask) { u32 val_tmp; - int retval; - retval = had_get_hwstate(intelhaddata); - if (retval) - return retval; + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + return -ENODEV; mid_hdmi_audio_read(intelhaddata, offset, &val_tmp); val_tmp &= ~mask; @@ -930,7 +913,7 @@ static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) { - u32 hdmi_status, i = 0; + u32 hdmi_status = 0, i = 0; /* Handle Underrun interrupt within Audio Unit */ had_write_register(intelhaddata, AUD_CONFIG, 0); @@ -977,7 +960,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) pm_runtime_get(intelhaddata->dev); - if (had_get_hwstate(intelhaddata)) { + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", __func__); retval = -ENODEV; @@ -1185,7 +1168,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* Disable local INTRs till register prgmng is done */ - if (had_get_hwstate(intelhaddata)) { + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "_START: HDMI cable plugged-out\n"); retval = -ENODEV; @@ -1245,7 +1228,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) runtime = substream->runtime; had_stream = &intelhaddata->stream_data; - if (had_get_hwstate(intelhaddata)) { + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", __func__); retval = -ENODEV; @@ -1329,6 +1312,9 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( intelhaddata = snd_pcm_substream_chip(substream); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + return SNDRV_PCM_POS_XRUN; + if (intelhaddata->flag_underrun) { intelhaddata->flag_underrun = false; return SNDRV_PCM_POS_XRUN; @@ -1614,7 +1600,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - if (had_get_hwstate(intelhaddata)) { + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "HDMI cable plugged-out\n"); return 0; } From 2e52f5e518fb79aca459fcd25c3b8f185aa4bcf7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 17:09:13 +0100 Subject: [PATCH 35/54] ALSA: x86: Tidy up codes Clean up codes, fix indentations, correct comments, etc. No functional change. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 148 ++++++++++++++--------------------- 1 file changed, 59 insertions(+), 89 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 7c6549a10c1c..46db4883f0b5 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -285,7 +285,7 @@ static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, reset); } -/** +/* * initialize audio channel status registers * This function is called in the prepare callback */ @@ -298,9 +298,9 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, int format; ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits & - IEC958_AES0_NONAUDIO)>>1; + IEC958_AES0_NONAUDIO) >> 1; ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & - IEC958_AES3_CON_CLOCK)>>4; + IEC958_AES3_CON_CLOCK) >> 4; cfg_val.cfg_regx_v2.val_bit = ch_stat0.status_0_regx.lpcm_id; switch (substream->runtime->rate) { @@ -330,9 +330,8 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, default: /* control should never come here */ return -EINVAL; - break; - } + had_write_register(intelhaddata, AUD_CH_STATUS_0, ch_stat0.status_0_regval); @@ -348,6 +347,7 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, ch_stat1.status_1_regx.max_wrd_len = 0; ch_stat1.status_1_regx.wrd_len = 0; } + had_write_register(intelhaddata, AUD_CH_STATUS_1, ch_stat1.status_1_regval); return 0; @@ -466,14 +466,14 @@ static int spk_to_chmap(int spk) static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) { - int i = 0, c = 0; + int i, c; int spk_mask = 0; struct snd_pcm_chmap_elem *chmap; u8 eld_high, eld_high_mask = 0xF0; u8 high_msb; chmap = kzalloc(sizeof(*chmap), GFP_KERNEL); - if (chmap == NULL) { + if (!chmap) { intelhaddata->chmap->chmap = NULL; return; } @@ -514,7 +514,7 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) for (c = 0; c < channel_allocations[i].channels; c++) { chmap->map[c] = spk_to_chmap( channel_allocations[i].speakers[ - (MAX_SPEAKERS - 1)-c]); + (MAX_SPEAKERS - 1) - c]); } chmap->channels = channel_allocations[i].channels; intelhaddata->chmap->chmap = chmap; @@ -550,12 +550,12 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, { struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct snd_intelhad *intelhaddata = info->private_data; - int i = 0; + int i; const struct snd_pcm_chmap_elem *chmap; if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) return -ENODEV; - if (intelhaddata->chmap->chmap == NULL) + if (!intelhaddata->chmap->chmap) return -ENODATA; chmap = intelhaddata->chmap->chmap; for (i = 0; i < chmap->channels; i++) @@ -567,7 +567,7 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, struct snd_pcm *pcm) { - int err = 0; + int err; err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, NULL, 0, (unsigned long)intelhaddata, @@ -615,7 +615,7 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation( intelhaddata, channels); - /*Calculte the byte wide checksum for all valid DIP words*/ + /* Calculte the byte wide checksum for all valid DIP words */ for (i = 0; i < BYTES_PER_WORD; i++) checksum += (info_frame >> i*BITS_PER_BYTE) & MASK_BYTE0; for (i = 0; i < BYTES_PER_WORD; i++) @@ -639,10 +639,8 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.ctrl_val); } -/** - * snd_intelhad_prog_buffer - programs buffer - * address and length registers - * +/* + * snd_intelhad_prog_buffer - programs buffer address and length registers * @substream:substream for which the prepare function is called * @intelhaddata:substream private data * @@ -684,7 +682,7 @@ static int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, intelhaddata->buf_info[i].buf_size = period_bytes; else intelhaddata->buf_info[i].buf_size = ring_buf_size - - (period_bytes*i); + (i * period_bytes); had_write_register(intelhaddata, AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH), @@ -728,7 +726,7 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) { u32 maud_val; - /* Select maud according to DP 1.2 spec*/ + /* Select maud according to DP 1.2 spec */ if (link_rate == DP_2_7_GHZ) { switch (aud_samp_freq) { case AUD_SAMPLE_RATE_32: @@ -836,41 +834,41 @@ static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, static int had_calculate_n_value(u32 aud_samp_freq) { - s32 n_val; + int n_val; /* Select N according to HDMI 1.3a spec*/ switch (aud_samp_freq) { case AUD_SAMPLE_RATE_32: n_val = 4096; - break; + break; case AUD_SAMPLE_RATE_44_1: n_val = 6272; - break; + break; case AUD_SAMPLE_RATE_48: n_val = 6144; - break; + break; case AUD_SAMPLE_RATE_88_2: n_val = 12544; - break; + break; case AUD_SAMPLE_RATE_96: n_val = 12288; - break; + break; case AUD_SAMPLE_RATE_176_4: n_val = 25088; - break; + break; case HAD_MAX_RATE: n_val = 24576; - break; + break; default: n_val = -EINVAL; - break; + break; } return n_val; } @@ -888,7 +886,7 @@ static int had_calculate_n_value(u32 aud_samp_freq) static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, struct snd_intelhad *intelhaddata) { - s32 n_val; + int n_val; if (intelhaddata->dp_output) { /* @@ -920,7 +918,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) /* Reset buffer pointers */ had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 1); had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 0); - /** + /* * The interrupt status 'sticky' bits might not be cleared by * setting '1' to that bit once... */ @@ -939,7 +937,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n"); } -/** +/* * snd_intelhad_open - stream initializations are done here * @substream:substream for which the stream function is called * @@ -1029,25 +1027,8 @@ static void had_period_elapsed(struct snd_pcm_substream *substream) snd_pcm_period_elapsed(substream); } -/** - * snd_intelhad_init_stream - internal function to initialize stream info - * @substream:substream for which the stream function is called - * - */ -static int snd_intelhad_init_stream(struct snd_pcm_substream *substream) -{ - struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); - - intelhaddata->stream_info.had_substream = substream; - intelhaddata->stream_info.buffer_ptr = 0; - intelhaddata->stream_info.buffer_rendered = 0; - intelhaddata->stream_info.sfreq = substream->runtime->rate; - return 0; -} - -/** - * snd_intelhad_close- to free parameteres when stream is stopped - * +/* + * snd_intelhad_close - to free parameteres when stream is stopped * @substream: substream for which the function is called * * This function is called by ALSA framework when stream is stopped @@ -1081,11 +1062,10 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) return 0; } -/** - * snd_intelhad_hw_params- to setup the hardware parameters - * like allocating the buffers - * - * @substream: substream for which the function is called +/* + * snd_intelhad_hw_params - to setup the hardware parameters + * like allocating the buffers + * @substream: substream for which the function is called * @hw_params: hardware parameters * * This function is called by ALSA framework when hardware params are set @@ -1121,14 +1101,12 @@ static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, return retval; } -/** - * snd_intelhad_hw_free- to release the resources allocated during - * hardware params setup - * +/* + * snd_intelhad_hw_free - to release the resources allocated during + * hardware params setup * @substream: substream for which the function is called * * This function is called by ALSA framework before close callback. - * */ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) { @@ -1146,10 +1124,11 @@ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) return 0; } -/** +/* * snd_intelhad_pcm_trigger - stream activities are handled here - * @substream:substream for which the stream function is called - * @cmd:the stream commamd thats requested from upper layer + * @substream: substream for which the stream function is called + * @cmd: the stream commamd thats requested from upper layer + * * This function is called whenever an a stream activity is invoked */ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, @@ -1208,10 +1187,9 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, return retval; } -/** - * snd_intelhad_pcm_prepare- internal preparation before starting a stream - * - * @substream: substream for which the function is called +/* + * snd_intelhad_pcm_prepare - internal preparation before starting a stream + * @substream: substream for which the function is called * * This function is called when a stream is started for internal preparation. */ @@ -1252,10 +1230,10 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) return retval; } - retval = snd_intelhad_init_stream(substream); - if (retval) - goto prep_end; - + intelhaddata->stream_info.had_substream = substream; + intelhaddata->stream_info.buffer_ptr = 0; + intelhaddata->stream_info.buffer_rendered = 0; + intelhaddata->stream_info.sfreq = substream->runtime->rate; /* Get N value in KHz */ disp_samp_freq = intelhaddata->tmds_clock_speed; @@ -1294,10 +1272,9 @@ prep_end: return retval; } -/** +/* * snd_intelhad_pcm_pointer- to send the current buffer pointerprocessed by hw - * - * @substream: substream for which the function is called + * @substream: substream for which the function is called * * This function is called by ALSA framework to get the current hw buffer ptr * when a period is elapsed @@ -1359,11 +1336,10 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( return intelhaddata->stream_info.buffer_ptr; } -/** +/* * snd_intelhad_pcm_mmap- mmaps a kernel buffer to user space for copying data - * - * @substream: substream for which the function is called - * @vma: struct instance of memory VMM memory area + * @substream: substream for which the function is called + * @vma: struct instance of memory VMM memory area * * This function is called by OS when a user space component * tries to get mmap memory from driver @@ -1418,11 +1394,9 @@ out: /* * hdmi_lpe_audio_suspend - power management suspend function - * * @pdev: platform device * - * This function is called by client driver to suspend the - * hdmi audio. + * This function is called to suspend the hdmi audio. */ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state) @@ -1465,11 +1439,9 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, /* * hdmi_lpe_audio_resume - power management resume function + * @pdev: platform device * - *@pdev: platform device - * - * This function is called by client driver to resume the - * hdmi audio. + * This function is called to resume the hdmi audio. */ static int hdmi_lpe_audio_resume(struct platform_device *pdev) { @@ -1605,7 +1577,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) return 0; } - /*Reprogram the registers with addr and length*/ + /* Reprogram the registers with addr and length */ had_write_register(intelhaddata, AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), buf_size); @@ -1939,8 +1911,7 @@ static void hdmi_lpe_audio_free(struct snd_card *card) * hdmi_lpe_audio_probe - start bridge with i915 * * This function is called when the i915 driver creates the - * hdmi-lpe-audio platform device. Card creation is deferred until a - * hot plug event is received + * hdmi-lpe-audio platform device. */ static int hdmi_lpe_audio_probe(struct platform_device *pdev) { @@ -2084,8 +2055,7 @@ err: /* * hdmi_lpe_audio_remove - stop bridge with i915 * - * This function is called when the platform device is destroyed. The sound - * card should have been removed on hot plug event. + * This function is called when the platform device is destroyed. */ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { From 4151ee845ad8230d18ac4a0e0bf1037180c6d2d9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 18:14:15 +0100 Subject: [PATCH 36/54] ALSA: x86: Remove _v[12] suffices Although we dropped the most of the obsoleted *_v1 definitions and codes, some codes still keep the _v1 or _v2 suffices. Now they are ripped off. The only thing to be done carefully here is the definition of control offsets. The original code defines enum hdmi_ctrl_reg_offset_v1 and a few new elements just for v2 on its top. After this cleanup, we remove the old AUD_HDMI_STATUS and AUD_HDMIW_INFOFR definitions and replace with the v2 values. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 46 ++++++++++++++++---------------- sound/x86/intel_hdmi_audio.h | 2 +- sound/x86/intel_hdmi_lpe_audio.h | 24 +++++------------ 3 files changed, 31 insertions(+), 41 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 46db4883f0b5..84b374cc183f 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -249,10 +249,10 @@ static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata, channels = substream->runtime->channels; else channels = 2; - cfg_val.cfg_regx_v2.num_ch = channels - 2; + cfg_val.cfg_regx.num_ch = channels - 2; data = data | cfg_val.cfg_regval; - mask = mask | AUD_CONFIG_CH_MASK_V2; + mask = mask | AUD_CONFIG_CH_MASK; dev_dbg(intelhaddata->dev, "%s : data = %x, mask =%x\n", __func__, data, mask); @@ -265,10 +265,10 @@ static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) u32 status_reg; if (enable) { - mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS_v2, &status_reg); + mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS, &status_reg); status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; - mid_hdmi_audio_write(ctx, AUD_HDMI_STATUS_v2, status_reg); - mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS_v2, &status_reg); + mid_hdmi_audio_write(ctx, AUD_HDMI_STATUS, status_reg); + mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS, &status_reg); } } @@ -282,7 +282,7 @@ static void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata, static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, u8 reset) { - had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, reset); + had_write_register(intelhaddata, AUD_HDMI_STATUS, reset); } /* @@ -301,7 +301,7 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, IEC958_AES0_NONAUDIO) >> 1; ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & IEC958_AES3_CON_CLOCK) >> 4; - cfg_val.cfg_regx_v2.val_bit = ch_stat0.status_0_regx.lpcm_id; + cfg_val.cfg_regx.val_bit = ch_stat0.status_0_regx.lpcm_id; switch (substream->runtime->rate) { case AUD_SAMPLE_RATE_32: @@ -367,19 +367,19 @@ static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, had_prog_status_reg(substream, intelhaddata); - buf_cfg.buf_cfg_regx_v2.audio_fifo_watermark = FIFO_THRESHOLD; - buf_cfg.buf_cfg_regx_v2.dma_fifo_watermark = DMA_FIFO_THRESHOLD; - buf_cfg.buf_cfg_regx_v2.aud_delay = 0; + buf_cfg.buf_cfg_regx.audio_fifo_watermark = FIFO_THRESHOLD; + buf_cfg.buf_cfg_regx.dma_fifo_watermark = DMA_FIFO_THRESHOLD; + buf_cfg.buf_cfg_regx.aud_delay = 0; had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.buf_cfgval); channels = substream->runtime->channels; - cfg_val.cfg_regx_v2.num_ch = channels - 2; + cfg_val.cfg_regx.num_ch = channels - 2; if (channels <= 2) - cfg_val.cfg_regx_v2.layout = LAYOUT0; + cfg_val.cfg_regx.layout = LAYOUT0; else - cfg_val.cfg_regx_v2.layout = LAYOUT1; + cfg_val.cfg_regx.layout = LAYOUT1; - cfg_val.cfg_regx_v2.val_bit = 1; + cfg_val.cfg_regx.val_bit = 1; had_write_register(intelhaddata, AUD_CONFIG, cfg_val.cfg_regval); return 0; } @@ -626,13 +626,13 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, frame2.fr2_regx.chksum = -(checksum); } - had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, info_frame); - had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, frame2.fr2_val); - had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, frame3.fr3_val); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, info_frame); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame2.fr2_val); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame3.fr3_val); /* program remaining DIP words with zero */ for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++) - had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, 0x0); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, 0x0); ctrl_state.ctrl_regx.dip_freq = 1; ctrl_state.ctrl_regx.dip_en_sta = 1; @@ -916,20 +916,20 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) /* Handle Underrun interrupt within Audio Unit */ had_write_register(intelhaddata, AUD_CONFIG, 0); /* Reset buffer pointers */ - had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 1); - had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 0); + had_write_register(intelhaddata, AUD_HDMI_STATUS, 1); + had_write_register(intelhaddata, AUD_HDMI_STATUS, 0); /* * The interrupt status 'sticky' bits might not be cleared by * setting '1' to that bit once... */ do { /* clear bit30, 31 AUD_HDMI_STATUS */ - had_read_register(intelhaddata, AUD_HDMI_STATUS_v2, + had_read_register(intelhaddata, AUD_HDMI_STATUS, &hdmi_status); dev_dbg(intelhaddata->dev, "HDMI status =0x%x\n", hdmi_status); if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { i++; had_write_register(intelhaddata, - AUD_HDMI_STATUS_v2, hdmi_status); + AUD_HDMI_STATUS, hdmi_status); } else break; } while (i < MAX_CNT); @@ -1812,7 +1812,7 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) struct snd_intelhad *ctx = dev_id; u32 audio_stat, audio_reg; - audio_reg = AUD_HDMI_STATUS_v2; + audio_reg = AUD_HDMI_STATUS; mid_hdmi_audio_read(ctx, audio_reg, &audio_stat); if (audio_stat & HDMI_AUDIO_UNDERRUN) { diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 4549c4d9d650..8b85a5668d83 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -69,7 +69,7 @@ #define LAYOUT0 0 #define LAYOUT1 1 #define SWAP_LFE_CENTER 0x00fac4c8 -#define AUD_CONFIG_CH_MASK_V2 0x70 +#define AUD_CONFIG_CH_MASK 0x70 struct pcm_stream_info { int str_id; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 8f320b4aa3b7..628c578ecedf 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -277,7 +277,7 @@ enum hdmi_ctrl_reg_offset_common { AUDIO_HDMI_CONFIG_C = 0x900, }; /* HDMI controller register offsets */ -enum hdmi_ctrl_reg_offset_v1 { +enum hdmi_ctrl_reg_offset { AUD_CONFIG = 0x0, AUD_CH_STATUS_0 = 0x08, AUD_CH_STATUS_1 = 0x0C, @@ -295,18 +295,8 @@ enum hdmi_ctrl_reg_offset_v1 { AUD_BUF_D_ADDR = 0x58, AUD_BUF_D_LENGTH = 0x5c, AUD_CNTL_ST = 0x60, - AUD_HDMI_STATUS = 0x68, - AUD_HDMIW_INFOFR = 0x114, -}; - -/* - * Delta changes in HDMI controller register offsets - * compare to v1 version - */ - -enum hdmi_ctrl_reg_offset_v2 { - AUD_HDMI_STATUS_v2 = 0x64, - AUD_HDMIW_INFOFR_v2 = 0x68, + AUD_HDMI_STATUS = 0x64, /* v2 */ + AUD_HDMIW_INFOFR = 0x68, /* v2 */ }; /* @@ -374,7 +364,7 @@ union aud_cfg { u32 bogus_sample:1; u32 dp_modei:1; u32 rsvd:16; - } cfg_regx_v2; + } cfg_regx; u32 cfg_regval; }; @@ -430,7 +420,7 @@ union aud_hdmi_cts { u32 cts_val:24; u32 en_cts_prog:1; u32 rsvd:7; - } cts_regx_v2; + } cts_regx; u32 cts_regval; }; @@ -446,7 +436,7 @@ union aud_hdmi_n_enable { u32 n_val:24; u32 en_n_prog:1; u32 rsvd:7; - } n_regx_v2; + } n_regx; u32 n_regval; }; @@ -464,7 +454,7 @@ union aud_buf_config { u32 rsvd0:5; u32 aud_delay:8; u32 rsvd1:8; - } buf_cfg_regx_v2; + } buf_cfg_regx; u32 buf_cfgval; }; From 4a5ddb2cb1ef624300d1e66e9e6974cd37b7012f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 16:45:38 +0100 Subject: [PATCH 37/54] ALSA: x86: Constfy tables Some tables can be defined as const. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 84b374cc183f..81b6c26a8646 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -51,7 +51,7 @@ MODULE_PARM_DESC(id, /* * ELD SA bits in the CEA Speaker Allocation data block */ -static int eld_speaker_allocation_bits[] = { +static const int eld_speaker_allocation_bits[] = { [0] = FL | FR, [1] = LFE, [2] = FC, @@ -114,7 +114,7 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { { .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, }; -static struct channel_map_table map_tables[] = { +static const struct channel_map_table map_tables[] = { { SNDRV_CHMAP_FL, 0x00, FL }, { SNDRV_CHMAP_FR, 0x01, FR }, { SNDRV_CHMAP_RL, 0x04, RL }, @@ -455,7 +455,7 @@ static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata, /* from speaker bit mask to ALSA API channel position */ static int spk_to_chmap(int spk) { - struct channel_map_table *t = map_tables; + const struct channel_map_table *t = map_tables; for (; t->map; t++) { if (t->spk_mask == spk) From bcce775ca8d66a5222ac2d28e5388b5a6c2d9ad6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 17:18:20 +0100 Subject: [PATCH 38/54] ALSA: x86: Remove superfluous irqsave flags We don't need to use irqsave/irqrestore versions for each spin lock, but judge the context properly and use the simpler versions. Also add some (still simplistic) comments to functions. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 71 +++++++++++++++++------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 81b6c26a8646..046af2367fba 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1135,7 +1135,6 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { int retval = 0; - unsigned long flag_irq; struct snd_intelhad *intelhaddata; struct had_stream_pvt *stream; struct had_stream_data *had_stream; @@ -1163,14 +1162,14 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_STOP: - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irq); + spin_lock(&intelhaddata->had_spinlock); intelhaddata->stream_info.str_id = 0; intelhaddata->curr_buf = 0; /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ had_stream->stream_type = HAD_INIT; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq); + spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ snd_intelhad_enable_audio_int(intelhaddata, false); snd_intelhad_enable_audio(intelhaddata, false); @@ -1402,7 +1401,6 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state) { struct had_stream_data *had_stream; - unsigned long flag_irqs; struct snd_pcm_substream *substream; struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); @@ -1414,15 +1412,15 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, return -EAGAIN; } - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); dev_dbg(intelhaddata->dev, "had not connected\n"); return 0; } if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); dev_dbg(intelhaddata->dev, "had already suspended\n"); return 0; } @@ -1432,7 +1430,7 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", __func__, __LINE__); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); snd_intelhad_enable_audio_int(intelhaddata, false); return 0; } @@ -1446,17 +1444,16 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, static int hdmi_lpe_audio_resume(struct platform_device *pdev) { struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - unsigned long flag_irqs; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); dev_dbg(intelhaddata->dev, "had not connected\n"); return 0; } if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); dev_dbg(intelhaddata->dev, "had is not in suspended state\n"); return 0; } @@ -1465,7 +1462,7 @@ static int hdmi_lpe_audio_resume(struct platform_device *pdev) dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); snd_intelhad_enable_audio_int(intelhaddata, true); return 0; } @@ -1477,7 +1474,6 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, enum intel_had_aud_buf_type buff_done; u32 buf_size, buf_addr; struct had_stream_data *had_stream; - unsigned long flag_irqs; had_stream = &intelhaddata->stream_data; @@ -1507,14 +1503,13 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, (buf_addr | BIT(0) | BIT(1))); } buf_id = buf_id % 4; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); intelhaddata->buff_done = buf_id; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); } return intr_count; } +/* called from irq handler */ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) { u32 len = 1; @@ -1525,15 +1520,15 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) struct had_stream_data *had_stream; int intr_count; enum had_status_stream stream_type; - unsigned long flag_irqs; + unsigned long flags; had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; intr_count = 1; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irqsave(&intelhaddata->had_spinlock, flags); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); dev_dbg(intelhaddata->dev, "%s:Device already disconnected\n", __func__); return 0; @@ -1551,16 +1546,16 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) /* Check for any intr_miss in case of active playback */ if (had_stream->stream_type == HAD_RUNNING_STREAM) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); intr_count = had_chk_intrmiss(intelhaddata, buf_id); if (!intr_count || (intr_count > 3)) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, + flags); dev_err(intelhaddata->dev, "HAD SW state in non-recoverable mode\n"); return 0; } buf_id += (intr_count - 1); buf_id = buf_id % 4; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); } intelhaddata->buf_info[buf_id].is_valid = true; @@ -1570,7 +1565,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) } else intelhaddata->curr_buf = buf_id + 1; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "HDMI cable plugged-out\n"); @@ -1604,19 +1599,20 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) return 0; } +/* called from irq handler */ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct pcm_stream_info *stream; struct had_stream_data *had_stream; enum had_status_stream stream_type; - unsigned long flag_irqs; + unsigned long flags; int drv_status; had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irqsave(&intelhaddata->had_spinlock, flags); buf_id = intelhaddata->curr_buf; stream_type = had_stream->stream_type; intelhaddata->buff_done = buf_id; @@ -1624,7 +1620,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (stream_type == HAD_RUNNING_STREAM) intelhaddata->curr_buf = HAD_BUF_TYPE_A; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); dev_dbg(intelhaddata->dev, "Enter:%s buf_id=%d, stream_type=%d\n", __func__, buf_id, stream_type); @@ -1646,20 +1642,20 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) return 0; } +/* process hot plug, called from wq */ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; struct had_stream_data *had_stream; - unsigned long flag_irqs; substream = intelhaddata->stream_info.had_substream; had_stream = &intelhaddata->stream_data; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { dev_dbg(intelhaddata->dev, "Device already connected\n"); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); return 0; } buf_id = intelhaddata->curr_buf; @@ -1668,7 +1664,7 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); dev_dbg(intelhaddata->dev, "Processing HOT_PLUG, buf_id = %d\n", buf_id); @@ -1686,20 +1682,20 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) return 0; } +/* process hot unplug, called from wq */ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct had_stream_data *had_stream; - unsigned long flag_irqs; had_stream = &intelhaddata->stream_data; buf_id = intelhaddata->curr_buf; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "Device already disconnected\n"); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); return 0; } else { @@ -1715,14 +1711,14 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) /* Report to above ALSA layer */ if (intelhaddata->stream_info.had_substream != NULL) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); snd_pcm_stop(intelhaddata->stream_info.had_substream, SNDRV_PCM_STATE_SETUP); - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irq(&intelhaddata->had_spinlock); } had_stream->stream_type = HAD_INIT; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; @@ -1922,7 +1918,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) int irq; struct resource *res_mmio; int ret; - unsigned long flags; dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); @@ -2034,10 +2029,10 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) if (ret) goto err; - spin_lock_irqsave(&pdata->lpe_audio_slock, flags); + spin_lock_irq(&pdata->lpe_audio_slock); pdata->notify_audio_lpe = notify_audio_lpe; pdata->notify_pending = false; - spin_unlock_irqrestore(&pdata->lpe_audio_slock, flags); + spin_unlock_irq(&pdata->lpe_audio_slock); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); From 8f8d1d7fe009c320d80ed1c7b0c1d3d48b538965 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 17:24:02 +0100 Subject: [PATCH 39/54] ALSA: x86: Fix racy access to chmap The access to chmap can be racy against the hotplug process, where it recreates the chmap on the fly. For protecting against it, a mutex is introduced in this patch. It's also used for protecting the change / reference of eld and state fields, too. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 32 +++++++++++++++++++++++--------- sound/x86/intel_hdmi_audio.h | 1 + 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 046af2367fba..c0cb59e6a89b 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -555,11 +555,17 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) return -ENODEV; - if (!intelhaddata->chmap->chmap) + + mutex_lock(&intelhaddata->mutex); + if (!intelhaddata->chmap->chmap) { + mutex_unlock(&intelhaddata->mutex); return -ENODATA; + } + chmap = intelhaddata->chmap->chmap; for (i = 0; i < chmap->channels; i++) ucontrol->value.integer.value[i] = chmap->map[i]; + mutex_unlock(&intelhaddata->mutex); return 0; } @@ -1352,6 +1358,7 @@ static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, vma->vm_end - vma->vm_start, vma->vm_page_prot); } +/* process mode change of the running stream; called in mutex */ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) { struct snd_pcm_substream *substream; @@ -1642,7 +1649,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) return 0; } -/* process hot plug, called from wq */ +/* process hot plug, called from wq with mutex locked */ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; @@ -1682,7 +1689,7 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) return 0; } -/* process hot unplug, called from wq */ +/* process hot unplug, called from wq with mutex locked */ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; @@ -1751,12 +1758,14 @@ static int had_iec958_get(struct snd_kcontrol *kcontrol, { struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); + mutex_lock(&intelhaddata->mutex); ucontrol->value.iec958.status[0] = (intelhaddata->aes_bits >> 0) & 0xff; ucontrol->value.iec958.status[1] = (intelhaddata->aes_bits >> 8) & 0xff; ucontrol->value.iec958.status[2] = (intelhaddata->aes_bits >> 16) & 0xff; ucontrol->value.iec958.status[3] = (intelhaddata->aes_bits >> 24) & 0xff; + mutex_unlock(&intelhaddata->mutex); return 0; } @@ -1775,16 +1784,19 @@ static int had_iec958_put(struct snd_kcontrol *kcontrol, { unsigned int val; struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); + int changed = 0; val = (ucontrol->value.iec958.status[0] << 0) | (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | (ucontrol->value.iec958.status[3] << 24); + mutex_lock(&intelhaddata->mutex); if (intelhaddata->aes_bits != val) { intelhaddata->aes_bits = val; - return 1; + changed = 1; } - return 1; + mutex_unlock(&intelhaddata->mutex); + return changed; } static struct snd_kcontrol_new had_control_iec958_mask = { @@ -1837,6 +1849,7 @@ static void had_audio_wq(struct work_struct *work) container_of(work, struct snd_intelhad, hdmi_audio_wq); struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data; + mutex_lock(&ctx->mutex); if (!pdata->hdmi_connected) { dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", __func__); @@ -1844,12 +1857,11 @@ static void had_audio_wq(struct work_struct *work) if (ctx->state != hdmi_connector_status_connected) { dev_dbg(ctx->dev, "%s: Already Unplugged!\n", __func__); - return; + } else { + ctx->state = hdmi_connector_status_disconnected; + had_process_hot_unplug(ctx); } - ctx->state = hdmi_connector_status_disconnected; - had_process_hot_unplug(ctx); - } else { struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; @@ -1888,6 +1900,7 @@ static void had_audio_wq(struct work_struct *work) hdmi_audio_mode_change(ctx); } } + mutex_unlock(&ctx->mutex); } /* release resources */ @@ -1948,6 +1961,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx = card->private_data; spin_lock_init(&ctx->had_spinlock); + mutex_init(&ctx->mutex); ctx->drv_status = HAD_DRV_DISCONNECTED; ctx->dev = &pdev->dev; ctx->card = card; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 8b85a5668d83..be24682e3946 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -139,6 +139,7 @@ struct snd_intelhad { void __iomem *mmio_start; unsigned int had_config_offset; struct work_struct hdmi_audio_wq; + struct mutex mutex; /* for protecting chmap, state and eld */ }; #endif /* _INTEL_HDMI_AUDIO_ */ From d0e9b1a23ca3dbe24e88c6671218b9031e37db96 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 17:37:36 +0100 Subject: [PATCH 40/54] ALSA: x86: Drop flag_underrun field The flag_underrun flag is used to indicate to escalate the XRUN reporting at the next position inquiry, but there is a much simpler method to achieve it: just call snd_pcm_stop_xrun(). Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 9 +-------- sound/x86/intel_hdmi_audio.h | 1 - 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index c0cb59e6a89b..9ecdd9ad0199 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1297,11 +1297,6 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) return SNDRV_PCM_POS_XRUN; - if (intelhaddata->flag_underrun) { - intelhaddata->flag_underrun = false; - return SNDRV_PCM_POS_XRUN; - } - /* Use a hw register to calculate sub-period position reports. * This makes PulseAudio happier. */ @@ -1642,8 +1637,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (stream_type == HAD_RUNNING_STREAM) { /* Report UNDERRUN error to above layers */ - intelhaddata->flag_underrun = true; - had_period_elapsed(stream->had_substream); + snd_pcm_stop_xrun(stream->had_substream); } return 0; @@ -1965,7 +1959,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->drv_status = HAD_DRV_DISCONNECTED; ctx->dev = &pdev->dev; ctx->card = card; - ctx->flag_underrun = false; ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; strcpy(card->driver, INTEL_HAD); strcpy(card->shortname, INTEL_HAD); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index be24682e3946..945f6831f1dd 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -123,7 +123,6 @@ struct snd_intelhad { enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; unsigned int aes_bits; - bool flag_underrun; struct had_stream_data stream_data; spinlock_t had_spinlock; enum intel_had_aud_buf_type buff_done; From 0e9c67d7c88ce7054288e3b61deb09bfa59f8920 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 17:53:19 +0100 Subject: [PATCH 41/54] ALSA: x86: Drop superfluous state field The state field keeps the connection state and it's basically as same as drv_status field. Drop this redundancy. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 56 ++++++++++++-------------------- sound/x86/intel_hdmi_audio.h | 3 +- sound/x86/intel_hdmi_lpe_audio.h | 6 ---- 3 files changed, 21 insertions(+), 44 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 9ecdd9ad0199..621be602addd 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1644,7 +1644,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) } /* process hot plug, called from wq with mutex locked */ -static int had_process_hot_plug(struct snd_intelhad *intelhaddata) +static void had_process_hot_plug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; @@ -1657,8 +1657,9 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { dev_dbg(intelhaddata->dev, "Device already connected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); - return 0; + return; } + buf_id = intelhaddata->curr_buf; intelhaddata->buff_done = buf_id; intelhaddata->drv_status = HAD_DRV_CONNECTED; @@ -1679,12 +1680,10 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) } had_build_channel_allocation_map(intelhaddata); - - return 0; } /* process hot unplug, called from wq with mutex locked */ -static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) +static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct had_stream_data *had_stream; @@ -1697,14 +1696,14 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "Device already disconnected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); - return 0; + return; - } else { - /* Disable Audio */ - snd_intelhad_enable_audio_int(intelhaddata, false); - snd_intelhad_enable_audio(intelhaddata, false); } + /* Disable Audio */ + snd_intelhad_enable_audio_int(intelhaddata, false); + snd_intelhad_enable_audio(intelhaddata, false); + intelhaddata->drv_status = HAD_DRV_DISCONNECTED; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", @@ -1722,8 +1721,6 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) spin_unlock_irq(&intelhaddata->had_spinlock); kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; - - return 0; } /* PCM operations structure and the calls back for the same */ @@ -1847,18 +1844,13 @@ static void had_audio_wq(struct work_struct *work) if (!pdata->hdmi_connected) { dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", __func__); - - if (ctx->state != hdmi_connector_status_connected) { - dev_dbg(ctx->dev, "%s: Already Unplugged!\n", - __func__); - } else { - ctx->state = hdmi_connector_status_disconnected; - had_process_hot_unplug(ctx); - } - + had_process_hot_unplug(ctx); } else { struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; + dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", + __func__, eld->port_id, pdata->tmds_clock_speed); + switch (eld->pipe_id) { case 0: ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; @@ -1877,22 +1869,15 @@ static void had_audio_wq(struct work_struct *work) memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld)); + ctx->dp_output = pdata->dp_output; + ctx->tmds_clock_speed = pdata->tmds_clock_speed; + ctx->link_rate = pdata->link_rate; + had_process_hot_plug(ctx); - ctx->state = hdmi_connector_status_connected; - - dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", - __func__, eld->port_id, pdata->tmds_clock_speed); - - if (pdata->tmds_clock_speed) { - ctx->tmds_clock_speed = pdata->tmds_clock_speed; - ctx->dp_output = pdata->dp_output; - ctx->link_rate = pdata->link_rate; - - /* Process mode change if stream is active */ - if (ctx->stream_data.stream_type == HAD_RUNNING_STREAM) - hdmi_audio_mode_change(ctx); - } + /* Process mode change if stream is active */ + if (ctx->stream_data.stream_type == HAD_RUNNING_STREAM) + hdmi_audio_mode_change(ctx); } mutex_unlock(&ctx->mutex); } @@ -1966,7 +1951,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->irq = -1; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq); - ctx->state = hdmi_connector_status_disconnected; card->private_free = hdmi_lpe_audio_free; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 945f6831f1dd..258396e61829 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -129,7 +129,6 @@ struct snd_intelhad { struct device *dev; struct snd_pcm_chmap *chmap; int underrun_count; - enum hdmi_connector_status state; int tmds_clock_speed; int link_rate; @@ -138,7 +137,7 @@ struct snd_intelhad { void __iomem *mmio_start; unsigned int had_config_offset; struct work_struct hdmi_audio_wq; - struct mutex mutex; /* for protecting chmap, state and eld */ + struct mutex mutex; /* for protecting chmap and eld */ }; #endif /* _INTEL_HDMI_AUDIO_ */ diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 628c578ecedf..1bc961522d0d 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -591,12 +591,6 @@ union aud_info_frame3 { u32 fr3_val; }; -enum hdmi_connector_status { - hdmi_connector_status_connected = 1, - hdmi_connector_status_disconnected = 2, - hdmi_connector_status_unknown = 3, -}; - #define HDMI_AUDIO_UNDERRUN (1UL<<31) #define HDMI_AUDIO_BUFFER_DONE (1UL<<29) From fa5dfe6a01481a8fa00469be42ea32beb468a501 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 22:03:26 +0100 Subject: [PATCH 42/54] ALSA: x86: Drop redundant had_stream_pvt The had_stream_pvt struct assigned to PCM runtime private data tracks merely the stream running status, and the very same information is carried by had_stream->stream_type. Kill it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 46 +++----------------------------- sound/x86/intel_hdmi_audio.h | 6 ----- sound/x86/intel_hdmi_lpe_audio.h | 15 ----------- 3 files changed, 4 insertions(+), 63 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 621be602addd..88e9a91f28a0 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -953,7 +953,6 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; - struct had_stream_pvt *stream; struct had_stream_data *had_stream; int retval; @@ -968,31 +967,16 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", __func__); retval = -ENODEV; - goto exit_put_handle; - } - - /* Check, if device already in use */ - if (runtime->private_data) { - dev_dbg(intelhaddata->dev, "Device already in use\n"); - retval = -EBUSY; - goto exit_put_handle; + goto error; } /* set the runtime hw parameter with local snd_pcm_hardware struct */ runtime->hw = snd_intel_hadstream; - stream = kzalloc(sizeof(*stream), GFP_KERNEL); - if (!stream) { - retval = -ENOMEM; - goto exit_put_handle; - } - stream->stream_status = STREAM_INIT; - runtime->private_data = stream; - retval = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (retval < 0) - goto exit_err; + goto error; /* Make sure, that the period size is always aligned * 64byte boundary @@ -1002,15 +986,12 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) if (retval < 0) { dev_dbg(intelhaddata->dev, "%s:step_size=64 failed,err=%d\n", __func__, retval); - goto exit_err; + goto error; } return retval; -exit_err: - kfree(stream); -exit_put_handle: + error: pm_runtime_put(intelhaddata->dev); - runtime->private_data = NULL; return retval; } @@ -1020,16 +1001,8 @@ exit_put_handle: */ static void had_period_elapsed(struct snd_pcm_substream *substream) { - struct had_stream_pvt *stream; - if (!substream || !substream->runtime) return; - stream = substream->runtime->private_data; - if (!stream) - return; - - if (stream->stream_status != STREAM_RUNNING) - return; snd_pcm_period_elapsed(substream); } @@ -1042,13 +1015,8 @@ static void had_period_elapsed(struct snd_pcm_substream *substream) static int snd_intelhad_close(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; - struct snd_pcm_runtime *runtime; intelhaddata = snd_pcm_substream_chip(substream); - runtime = substream->runtime; - - if (WARN_ON(!runtime->private_data)) - return 0; intelhaddata->stream_info.buffer_rendered = 0; intelhaddata->stream_info.buffer_ptr = 0; @@ -1062,8 +1030,6 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); } - kfree(runtime->private_data); - runtime->private_data = NULL; pm_runtime_put(intelhaddata->dev); return 0; } @@ -1142,11 +1108,9 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, { int retval = 0; struct snd_intelhad *intelhaddata; - struct had_stream_pvt *stream; struct had_stream_data *had_stream; intelhaddata = snd_pcm_substream_chip(substream); - stream = substream->runtime->private_data; had_stream = &intelhaddata->stream_data; switch (cmd) { @@ -1158,7 +1122,6 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, retval = -ENODEV; break; } - stream->stream_status = STREAM_RUNNING; had_stream->stream_type = HAD_RUNNING_STREAM; @@ -1182,7 +1145,6 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, /* Reset buffer pointers */ snd_intelhad_reset_audio(intelhaddata, 1); snd_intelhad_reset_audio(intelhaddata, 0); - stream->stream_status = STREAM_DROPPED; snd_intelhad_enable_audio_int(intelhaddata, false); break; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 258396e61829..3bd2bb60f1f1 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -86,12 +86,6 @@ struct ring_buf_info { u8 is_valid; }; -struct had_stream_pvt { - enum had_stream_status stream_status; - int stream_ops; - ssize_t dbg_cum_bytes; -}; - struct had_stream_data { enum had_status_stream stream_type; }; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 1bc961522d0d..483b9feeff30 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -223,21 +223,6 @@ union otm_hdmi_eld_t { } __packed; }; -/** - * enum had_status - Audio stream states - * - * @STREAM_INIT: Stream initialized - * @STREAM_RUNNING: Stream running - * @STREAM_PAUSED: Stream paused - * @STREAM_DROPPED: Stream dropped - */ -enum had_stream_status { - STREAM_INIT = 0, - STREAM_RUNNING = 1, - STREAM_PAUSED = 2, - STREAM_DROPPED = 3 -}; - /** * enum had_status_stream - HAD stream states */ From 7d9e79869ba2a8a552f4c2cf1df44cf9a0822f02 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 22:25:58 +0100 Subject: [PATCH 43/54] ALSA: x86: Drop unused fields from pcm_stream_info The struct pcm_stream_info contains a few unused or useless fields. str_id is always zero, buffer_ptr is volatile, never read, and sfreq is nowhere referred. Kill them. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 19 +------------------ sound/x86/intel_hdmi_audio.h | 3 --- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 88e9a91f28a0..907e420cd90d 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1019,8 +1019,6 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); intelhaddata->stream_info.buffer_rendered = 0; - intelhaddata->stream_info.buffer_ptr = 0; - intelhaddata->stream_info.str_id = 0; intelhaddata->stream_info.had_substream = NULL; /* Check if following drv_status modification is required - VA */ @@ -1132,7 +1130,6 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: spin_lock(&intelhaddata->had_spinlock); - intelhaddata->stream_info.str_id = 0; intelhaddata->curr_buf = 0; /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ @@ -1188,19 +1185,8 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate); dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels); - if (intelhaddata->stream_info.str_id) { - dev_dbg(intelhaddata->dev, - "_prepare is called for existing str_id#%d\n", - intelhaddata->stream_info.str_id); - retval = snd_intelhad_pcm_trigger(substream, - SNDRV_PCM_TRIGGER_STOP); - return retval; - } - intelhaddata->stream_info.had_substream = substream; - intelhaddata->stream_info.buffer_ptr = 0; intelhaddata->stream_info.buffer_rendered = 0; - intelhaddata->stream_info.sfreq = substream->runtime->rate; /* Get N value in KHz */ disp_samp_freq = intelhaddata->tmds_clock_speed; @@ -1292,10 +1278,7 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( intelhaddata->stream_info.ring_buf_size, &(bytes_rendered)); - intelhaddata->stream_info.buffer_ptr = bytes_to_frames( - substream->runtime, - bytes_rendered + t); - return intelhaddata->stream_info.buffer_ptr; + return bytes_to_frames(substream->runtime, bytes_rendered + t); } /* diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 3bd2bb60f1f1..7bd273ec3275 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -72,12 +72,9 @@ #define AUD_CONFIG_CH_MASK 0x70 struct pcm_stream_info { - int str_id; struct snd_pcm_substream *had_substream; - u32 buffer_ptr; u64 buffer_rendered; u32 ring_buf_size; - int sfreq; }; struct ring_buf_info { From 313d9f28c1d5e0254ca16f2df0f1b737e30c0993 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 13:00:12 +0100 Subject: [PATCH 44/54] ALSA: x86: Properly manage PCM substream lifetype The PCM substream is referred not only in the PCM callbacks but also in the irq handler and in the hotplug/unplug codes. The latter code paths don't take the PCM lock, thus the PCM may be released unexpectedly while calling PCM helper functions or accessing pcm->runtime fields. This patch implements a simple refcount to assure the PCM substream accessibility while the other codes are accessing. It needed some code refactoring in the relevant functions for avoiding the doubly spinlocks. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 171 ++++++++++++++++++++--------------- sound/x86/intel_hdmi_audio.h | 3 +- 2 files changed, 99 insertions(+), 75 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 907e420cd90d..c209d9498c0e 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -154,6 +154,36 @@ static const struct snd_pcm_hardware snd_intel_hadstream = { .fifo_size = HAD_FIFO_SIZE, }; +/* Get the active PCM substream; + * Call had_substream_put() for unreferecing. + * Don't call this inside had_spinlock, as it takes by itself + */ +static struct snd_pcm_substream * +had_substream_get(struct snd_intelhad *intelhaddata) +{ + struct snd_pcm_substream *substream; + unsigned long flags; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flags); + substream = intelhaddata->stream_info.substream; + if (substream) + intelhaddata->stream_info.substream_refcount++; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); + return substream; +} + +/* Unref the active PCM substream; + * Don't call this inside had_spinlock, as it takes by itself + */ +static void had_substream_put(struct snd_intelhad *intelhaddata) +{ + unsigned long flags; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flags); + intelhaddata->stream_info.substream_refcount--; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); +} + /* Register access functions */ static inline void mid_hdmi_audio_read(struct snd_intelhad *ctx, u32 reg, u32 *val) @@ -215,7 +245,8 @@ static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, } /* - * function to read-modify AUD_CONFIG register on VLV2. + * enable / disable audio configuration + * * The had_read_modify() function should not directly be used on VLV2 for * updating AUD_CONFIG register. * This is because: @@ -227,39 +258,33 @@ static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, * causes the "channels" field to be updated as 0xy binary resulting in * bad audio. The fix is to always write the AUD_CONFIG[6:4] with * appropriate value when doing read-modify of AUD_CONFIG register. - * - * @substream: the current substream or NULL if no active substream - * @data : data to be written - * @mask : mask - * */ -static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata, - u32 data, u32 mask) +static void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata, + bool enable) { - struct snd_pcm_substream *substream; union aud_cfg cfg_val = {.cfg_regval = 0}; - u8 channels; + u8 channels, data, mask; /* * If substream is NULL, there is no active stream. * In this case just set channels to 2 */ - substream = intelhaddata->stream_info.had_substream; - if (substream && substream->runtime) - channels = substream->runtime->channels; - else - channels = 2; + channels = substream ? substream->runtime->channels : 2; cfg_val.cfg_regx.num_ch = channels - 2; - data = data | cfg_val.cfg_regval; - mask = mask | AUD_CONFIG_CH_MASK; + data = cfg_val.cfg_regval; + if (enable) + data |= 1; + mask = AUD_CONFIG_CH_MASK | 1; dev_dbg(intelhaddata->dev, "%s : data = %x, mask =%x\n", __func__, data, mask); - return had_read_modify(intelhaddata, AUD_CONFIG, data, mask); + had_read_modify(intelhaddata, AUD_CONFIG, data, mask); } +/* enable / disable the audio interface */ static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) { u32 status_reg; @@ -272,13 +297,6 @@ static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) } } -static void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata, - bool enable) -{ - had_read_modify_aud_config_v2(intelhaddata, enable ? BIT(0) : 0, - BIT(0)); -} - static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, u8 reset) { @@ -647,21 +665,17 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, /* * snd_intelhad_prog_buffer - programs buffer address and length registers - * @substream:substream for which the prepare function is called - * @intelhaddata:substream private data + * @substream: substream for which the prepare function is called + * @intelhaddata: substream private data * * This function programs ring buffer address and length into registers. */ -static int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, - int start, int end) +static int snd_intelhad_prog_buffer(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata, + int start, int end) { u32 ring_buf_addr, ring_buf_size, period_bytes; u8 i, num_periods; - struct snd_pcm_substream *substream; - - substream = intelhaddata->stream_info.had_substream; - if (WARN_ON(!substream)) - return 0; ring_buf_addr = substream->runtime->dma_addr; ring_buf_size = snd_pcm_lib_buffer_bytes(substream); @@ -989,23 +1003,17 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) goto error; } + spin_lock_irq(&intelhaddata->had_spinlock); + intelhaddata->stream_info.substream = substream; + intelhaddata->stream_info.substream_refcount++; + spin_unlock_irq(&intelhaddata->had_spinlock); + return retval; error: pm_runtime_put(intelhaddata->dev); return retval; } -/* - * had_period_elapsed - updates the hardware pointer status - * @had_substream: substream for which the stream function is called - */ -static void had_period_elapsed(struct snd_pcm_substream *substream) -{ - if (!substream || !substream->runtime) - return; - snd_pcm_period_elapsed(substream); -} - /* * snd_intelhad_close - to free parameteres when stream is stopped * @substream: substream for which the function is called @@ -1019,7 +1027,15 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); intelhaddata->stream_info.buffer_rendered = 0; - intelhaddata->stream_info.had_substream = NULL; + spin_lock_irq(&intelhaddata->had_spinlock); + intelhaddata->stream_info.substream = NULL; + intelhaddata->stream_info.substream_refcount--; + while (intelhaddata->stream_info.substream_refcount > 0) { + spin_unlock_irq(&intelhaddata->had_spinlock); + cpu_relax(); + spin_lock_irq(&intelhaddata->had_spinlock); + } + spin_unlock_irq(&intelhaddata->had_spinlock); /* Check if following drv_status modification is required - VA */ if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { @@ -1125,7 +1141,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, /* Enable Audio */ snd_intelhad_enable_audio_int(intelhaddata, true); - snd_intelhad_enable_audio(intelhaddata, true); + snd_intelhad_enable_audio(substream, intelhaddata, true); break; case SNDRV_PCM_TRIGGER_STOP: @@ -1138,7 +1154,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ snd_intelhad_enable_audio_int(intelhaddata, false); - snd_intelhad_enable_audio(intelhaddata, false); + snd_intelhad_enable_audio(substream, intelhaddata, false); /* Reset buffer pointers */ snd_intelhad_reset_audio(intelhaddata, 1); snd_intelhad_reset_audio(intelhaddata, 0); @@ -1185,7 +1201,6 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate); dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels); - intelhaddata->stream_info.had_substream = substream; intelhaddata->stream_info.buffer_rendered = 0; /* Get N value in KHz */ @@ -1211,7 +1226,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) retval = snd_intelhad_audio_ctrl(substream, intelhaddata); /* Prog buffer address */ - retval = snd_intelhad_prog_buffer(intelhaddata, + retval = snd_intelhad_prog_buffer(substream, intelhaddata, HAD_BUF_TYPE_A, HAD_BUF_TYPE_D); /* @@ -1306,12 +1321,12 @@ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) u32 disp_samp_freq, n_param; u32 link_rate = 0; - substream = intelhaddata->stream_info.had_substream; - if (!substream || !substream->runtime) + substream = had_substream_get(intelhaddata); + if (!substream) return 0; /* Disable Audio */ - snd_intelhad_enable_audio(intelhaddata, false); + snd_intelhad_enable_audio(substream, intelhaddata, false); /* Update CTS value */ disp_samp_freq = intelhaddata->tmds_clock_speed; @@ -1332,9 +1347,10 @@ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) n_param, intelhaddata); /* Enable Audio */ - snd_intelhad_enable_audio(intelhaddata, true); + snd_intelhad_enable_audio(substream, intelhaddata, true); out: + had_substream_put(intelhaddata); return retval; } @@ -1348,11 +1364,9 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state) { struct had_stream_data *had_stream; - struct snd_pcm_substream *substream; struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); had_stream = &intelhaddata->stream_data; - substream = intelhaddata->stream_info.had_substream; if (!pm_runtime_status_suspended(intelhaddata->dev)) { dev_err(intelhaddata->dev, "audio stream is active\n"); @@ -1463,10 +1477,10 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) enum intel_had_aud_buf_type buf_id; enum intel_had_aud_buf_type buff_done; struct pcm_stream_info *stream; + struct snd_pcm_substream *substream; u32 buf_size; struct had_stream_data *had_stream; int intr_count; - enum had_status_stream stream_type; unsigned long flags; had_stream = &intelhaddata->stream_data; @@ -1484,7 +1498,6 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) intelhaddata->buff_done = buf_id; buff_done = intelhaddata->buff_done; buf_size = intelhaddata->buf_info[buf_id].buf_size; - stream_type = had_stream->stream_type; /* Every debug statement has an implication * of ~5msec. Thus, avoid having >3 debug statements @@ -1536,11 +1549,13 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) /* In case of actual data, * report buffer_done to above ALSA layer */ - buf_size = intelhaddata->buf_info[buf_id].buf_size; - if (stream_type >= HAD_RUNNING_STREAM) { + substream = had_substream_get(intelhaddata); + if (substream) { + buf_size = intelhaddata->buf_info[buf_id].buf_size; intelhaddata->stream_info.buffer_rendered += (intr_count * buf_size); - had_period_elapsed(stream->had_substream); + snd_pcm_period_elapsed(substream); + had_substream_put(intelhaddata); } return 0; @@ -1552,6 +1567,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) enum intel_had_aud_buf_type buf_id; struct pcm_stream_info *stream; struct had_stream_data *had_stream; + struct snd_pcm_substream *substream; enum had_status_stream stream_type; unsigned long flags; int drv_status; @@ -1582,7 +1598,11 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (stream_type == HAD_RUNNING_STREAM) { /* Report UNDERRUN error to above layers */ - snd_pcm_stop_xrun(stream->had_substream); + substream = had_substream_get(intelhaddata); + if (substream) { + snd_pcm_stop_xrun(substream); + had_substream_put(intelhaddata); + } } return 0; @@ -1595,7 +1615,6 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) struct snd_pcm_substream *substream; struct had_stream_data *had_stream; - substream = intelhaddata->stream_info.had_substream; had_stream = &intelhaddata->stream_data; spin_lock_irq(&intelhaddata->had_spinlock); @@ -1617,11 +1636,13 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) buf_id); /* Safety check */ + substream = had_substream_get(intelhaddata); if (substream) { dev_dbg(intelhaddata->dev, "Force to stop the active stream by disconnection\n"); /* Set runtime->state to hw_params done */ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + had_substream_put(intelhaddata); } had_build_channel_allocation_map(intelhaddata); @@ -1632,38 +1653,40 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct had_stream_data *had_stream; + struct snd_pcm_substream *substream; had_stream = &intelhaddata->stream_data; buf_id = intelhaddata->curr_buf; + substream = had_substream_get(intelhaddata); + spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "Device already disconnected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); - return; + goto out; } /* Disable Audio */ snd_intelhad_enable_audio_int(intelhaddata, false); - snd_intelhad_enable_audio(intelhaddata, false); + snd_intelhad_enable_audio(substream, intelhaddata, false); intelhaddata->drv_status = HAD_DRV_DISCONNECTED; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); - - /* Report to above ALSA layer */ - if (intelhaddata->stream_info.had_substream != NULL) { - spin_unlock_irq(&intelhaddata->had_spinlock); - snd_pcm_stop(intelhaddata->stream_info.had_substream, - SNDRV_PCM_STATE_SETUP); - spin_lock_irq(&intelhaddata->had_spinlock); - } - had_stream->stream_type = HAD_INIT; spin_unlock_irq(&intelhaddata->had_spinlock); + + /* Report to above ALSA layer */ + if (substream) + snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + + out: + if (substream) + had_substream_put(intelhaddata); kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; } diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 7bd273ec3275..6e5a1978e9c7 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -72,9 +72,10 @@ #define AUD_CONFIG_CH_MASK 0x70 struct pcm_stream_info { - struct snd_pcm_substream *had_substream; + struct snd_pcm_substream *substream; u64 buffer_rendered; u32 ring_buf_size; + int substream_refcount; }; struct ring_buf_info { From 182cdf23dbf6672954ac646871bf5902050268c7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 14:43:39 +0100 Subject: [PATCH 45/54] ALSA: x86: Implement runtime PM Although the driver has some PM callbacks, it doesn't do it right: - the suspend callback doesn't handle to suspend the running PCM, - the runtime PM ops are missing, - pm_runtime_get_sync() isn't used at the right place. This patch covers the above and provides the basic runtime PM functionality. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 127 ++++++++++++++--------------------- 1 file changed, 50 insertions(+), 77 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index c209d9498c0e..04ff7f14fe12 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -975,7 +975,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) runtime = substream->runtime; intelhaddata->underrun_count = 0; - pm_runtime_get(intelhaddata->dev); + pm_runtime_get_sync(intelhaddata->dev); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", @@ -1129,6 +1129,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: /* Disable local INTRs till register prgmng is done */ if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, @@ -1145,6 +1147,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: spin_lock(&intelhaddata->had_spinlock); intelhaddata->curr_buf = 0; @@ -1354,80 +1358,6 @@ out: return retval; } -/* - * hdmi_lpe_audio_suspend - power management suspend function - * @pdev: platform device - * - * This function is called to suspend the hdmi audio. - */ -static int hdmi_lpe_audio_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct had_stream_data *had_stream; - struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - - had_stream = &intelhaddata->stream_data; - - if (!pm_runtime_status_suspended(intelhaddata->dev)) { - dev_err(intelhaddata->dev, "audio stream is active\n"); - return -EAGAIN; - } - - spin_lock_irq(&intelhaddata->had_spinlock); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irq(&intelhaddata->had_spinlock); - dev_dbg(intelhaddata->dev, "had not connected\n"); - return 0; - } - - if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { - spin_unlock_irq(&intelhaddata->had_spinlock); - dev_dbg(intelhaddata->dev, "had already suspended\n"); - return 0; - } - - intelhaddata->drv_status = HAD_DRV_SUSPENDED; - dev_dbg(intelhaddata->dev, - "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", - __func__, __LINE__); - - spin_unlock_irq(&intelhaddata->had_spinlock); - snd_intelhad_enable_audio_int(intelhaddata, false); - return 0; -} - -/* - * hdmi_lpe_audio_resume - power management resume function - * @pdev: platform device - * - * This function is called to resume the hdmi audio. - */ -static int hdmi_lpe_audio_resume(struct platform_device *pdev) -{ - struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - - spin_lock_irq(&intelhaddata->had_spinlock); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irq(&intelhaddata->had_spinlock); - dev_dbg(intelhaddata->dev, "had not connected\n"); - return 0; - } - - if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { - spin_unlock_irq(&intelhaddata->had_spinlock); - dev_dbg(intelhaddata->dev, "had is not in suspended state\n"); - return 0; - } - - intelhaddata->drv_status = HAD_DRV_CONNECTED; - dev_dbg(intelhaddata->dev, - "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", - __func__, __LINE__); - spin_unlock_irq(&intelhaddata->had_spinlock); - snd_intelhad_enable_audio_int(intelhaddata, true); - return 0; -} - static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, enum intel_had_aud_buf_type buf_id) { @@ -1808,6 +1738,7 @@ static void had_audio_wq(struct work_struct *work) container_of(work, struct snd_intelhad, hdmi_audio_wq); struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data; + pm_runtime_get_sync(ctx->dev); mutex_lock(&ctx->mutex); if (!pdata->hdmi_connected) { dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", @@ -1848,6 +1779,44 @@ static void had_audio_wq(struct work_struct *work) hdmi_audio_mode_change(ctx); } mutex_unlock(&ctx->mutex); + pm_runtime_put(ctx->dev); +} + +/* + * PM callbacks + */ + +static int hdmi_lpe_audio_runtime_suspend(struct device *dev) +{ + struct snd_intelhad *ctx = dev_get_drvdata(dev); + struct snd_pcm_substream *substream; + + substream = had_substream_get(ctx); + if (substream) { + snd_pcm_suspend(substream); + had_substream_put(ctx); + } + + return 0; +} + +static int hdmi_lpe_audio_suspend(struct device *dev) +{ + struct snd_intelhad *ctx = dev_get_drvdata(dev); + int err; + + err = hdmi_lpe_audio_runtime_suspend(dev); + if (!err) + snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D3hot); + return err; +} + +static int hdmi_lpe_audio_resume(struct device *dev) +{ + struct snd_intelhad *ctx = dev_get_drvdata(dev); + + snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D0); + return 0; } /* release resources */ @@ -2021,14 +1990,18 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops hdmi_lpe_audio_pm = { + SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume) + SET_RUNTIME_PM_OPS(hdmi_lpe_audio_runtime_suspend, NULL, NULL) +}; + static struct platform_driver hdmi_lpe_audio_driver = { .driver = { .name = "hdmi-lpe-audio", + .pm = &hdmi_lpe_audio_pm, }, .probe = hdmi_lpe_audio_probe, .remove = hdmi_lpe_audio_remove, - .suspend = hdmi_lpe_audio_suspend, - .resume = hdmi_lpe_audio_resume }; module_platform_driver(hdmi_lpe_audio_driver); From f69bd104b5cded0db547636fddd9512d7e6cfbf3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 14:57:22 +0100 Subject: [PATCH 46/54] ALSA: x86: Move stream status into pcm_stream_info The only remaining field in struct had_stream_data is stream_type that holds the current stream status. Such information fits better in struct pcm_stream_info, so move it as a boolean "running" field to be clearer. This allows us to get rid or had_stream_data definition and references. Also, the superfluous status check get removed in a couple of places where we can call PCM helpers in anyway. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 50 +++++++++----------------------- sound/x86/intel_hdmi_audio.h | 6 +--- sound/x86/intel_hdmi_lpe_audio.h | 8 ----- 3 files changed, 14 insertions(+), 50 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 04ff7f14fe12..985b7e8d4eae 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -967,11 +967,9 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; - struct had_stream_data *had_stream; int retval; intelhaddata = snd_pcm_substream_chip(substream); - had_stream = &intelhaddata->stream_data; runtime = substream->runtime; intelhaddata->underrun_count = 0; @@ -1122,10 +1120,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, { int retval = 0; struct snd_intelhad *intelhaddata; - struct had_stream_data *had_stream; intelhaddata = snd_pcm_substream_chip(substream); - had_stream = &intelhaddata->stream_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1139,7 +1135,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, break; } - had_stream->stream_type = HAD_RUNNING_STREAM; + intelhaddata->stream_info.running = true; /* Enable Audio */ snd_intelhad_enable_audio_int(intelhaddata, true); @@ -1154,7 +1150,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ - had_stream->stream_type = HAD_INIT; + intelhaddata->stream_info.running = false; spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ snd_intelhad_enable_audio_int(intelhaddata, false); @@ -1184,11 +1180,9 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) u32 link_rate = 0; struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; - struct had_stream_data *had_stream; intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - had_stream = &intelhaddata->stream_data; if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", @@ -1364,9 +1358,6 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, int i, intr_count = 0; enum intel_had_aud_buf_type buff_done; u32 buf_size, buf_addr; - struct had_stream_data *had_stream; - - had_stream = &intelhaddata->stream_data; buff_done = buf_id; @@ -1409,11 +1400,9 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) struct pcm_stream_info *stream; struct snd_pcm_substream *substream; u32 buf_size; - struct had_stream_data *had_stream; int intr_count; unsigned long flags; - had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; intr_count = 1; @@ -1435,7 +1424,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) */ /* Check for any intr_miss in case of active playback */ - if (had_stream->stream_type == HAD_RUNNING_STREAM) { + if (stream->running) { intr_count = had_chk_intrmiss(intelhaddata, buf_id); if (!intr_count || (intr_count > 3)) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, @@ -1450,7 +1439,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) intelhaddata->buf_info[buf_id].is_valid = true; if (intelhaddata->valid_buf_cnt-1 == buf_id) { - if (had_stream->stream_type >= HAD_RUNNING_STREAM) + if (stream->running) intelhaddata->curr_buf = HAD_BUF_TYPE_A; } else intelhaddata->curr_buf = buf_id + 1; @@ -1496,27 +1485,23 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct pcm_stream_info *stream; - struct had_stream_data *had_stream; struct snd_pcm_substream *substream; - enum had_status_stream stream_type; unsigned long flags; int drv_status; - had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; spin_lock_irqsave(&intelhaddata->had_spinlock, flags); buf_id = intelhaddata->curr_buf; - stream_type = had_stream->stream_type; intelhaddata->buff_done = buf_id; drv_status = intelhaddata->drv_status; - if (stream_type == HAD_RUNNING_STREAM) + if (stream->running) intelhaddata->curr_buf = HAD_BUF_TYPE_A; spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); - dev_dbg(intelhaddata->dev, "Enter:%s buf_id=%d, stream_type=%d\n", - __func__, buf_id, stream_type); + dev_dbg(intelhaddata->dev, "Enter:%s buf_id=%d, stream_running=%d\n", + __func__, buf_id, stream->running); snd_intelhad_handle_underrun(intelhaddata); @@ -1526,13 +1511,11 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) return 0; } - if (stream_type == HAD_RUNNING_STREAM) { - /* Report UNDERRUN error to above layers */ - substream = had_substream_get(intelhaddata); - if (substream) { - snd_pcm_stop_xrun(substream); - had_substream_put(intelhaddata); - } + /* Report UNDERRUN error to above layers */ + substream = had_substream_get(intelhaddata); + if (substream) { + snd_pcm_stop_xrun(substream); + had_substream_put(intelhaddata); } return 0; @@ -1543,9 +1526,6 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; - struct had_stream_data *had_stream; - - had_stream = &intelhaddata->stream_data; spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { @@ -1582,10 +1562,8 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; - struct had_stream_data *had_stream; struct snd_pcm_substream *substream; - had_stream = &intelhaddata->stream_data; buf_id = intelhaddata->curr_buf; substream = had_substream_get(intelhaddata); @@ -1607,7 +1585,6 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); - had_stream->stream_type = HAD_INIT; spin_unlock_irq(&intelhaddata->had_spinlock); /* Report to above ALSA layer */ @@ -1775,8 +1752,7 @@ static void had_audio_wq(struct work_struct *work) had_process_hot_plug(ctx); /* Process mode change if stream is active */ - if (ctx->stream_data.stream_type == HAD_RUNNING_STREAM) - hdmi_audio_mode_change(ctx); + hdmi_audio_mode_change(ctx); } mutex_unlock(&ctx->mutex); pm_runtime_put(ctx->dev); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 6e5a1978e9c7..2804e94a6710 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -76,6 +76,7 @@ struct pcm_stream_info { u64 buffer_rendered; u32 ring_buf_size; int substream_refcount; + bool running; }; struct ring_buf_info { @@ -84,10 +85,6 @@ struct ring_buf_info { u8 is_valid; }; -struct had_stream_data { - enum had_status_stream stream_type; -}; - /** * struct snd_intelhad - intelhad driver structure * @@ -115,7 +112,6 @@ struct snd_intelhad { enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; unsigned int aes_bits; - struct had_stream_data stream_data; spinlock_t had_spinlock; enum intel_had_aud_buf_type buff_done; struct device *dev; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 483b9feeff30..1e7e6db987c6 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -223,14 +223,6 @@ union otm_hdmi_eld_t { } __packed; }; -/** - * enum had_status_stream - HAD stream states - */ -enum had_status_stream { - HAD_INIT = 0, - HAD_RUNNING_STREAM, -}; - enum had_drv_status { HAD_DRV_CONNECTED, HAD_DRV_RUNNING, From df0435db1db9e385acdc0a354896d2c0e878dbd5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 15:37:11 +0100 Subject: [PATCH 47/54] ALSA: x86: Use the standard ELD bytes definitions We have some constants defined in drm/drm_edid.h, and clean up our own definitions. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 14 ++-- sound/x86/intel_hdmi_audio.h | 3 +- sound/x86/intel_hdmi_lpe_audio.h | 119 ------------------------------- 3 files changed, 9 insertions(+), 127 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 985b7e8d4eae..496d3e92b2a8 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -451,7 +451,7 @@ static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata, */ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (intelhaddata->eld.speaker_allocation_block & (1 << i)) + if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i)) spk_mask |= eld_speaker_allocation_bits[i]; } @@ -496,8 +496,8 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) return; } - dev_dbg(intelhaddata->dev, "eld.speaker_allocation_block = %x\n", - intelhaddata->eld.speaker_allocation_block); + dev_dbg(intelhaddata->dev, "eld speaker = %x\n", + intelhaddata->eld[DRM_ELD_SPEAKER]); /* WA: Fix the max channel supported to 8 */ @@ -508,14 +508,14 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) */ /* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */ - eld_high = intelhaddata->eld.speaker_allocation_block & eld_high_mask; + eld_high = intelhaddata->eld[DRM_ELD_SPEAKER] & eld_high_mask; if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) { /* eld_high & (eld_high-1): if more than 1 bit set */ /* 0x1F: 7 channels */ for (i = 1; i < 4; i++) { high_msb = eld_high & (0x80 >> i); if (high_msb) { - intelhaddata->eld.speaker_allocation_block &= + intelhaddata->eld[DRM_ELD_SPEAKER] &= high_msb | 0xF; break; } @@ -523,7 +523,7 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) } for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (intelhaddata->eld.speaker_allocation_block & (1 << i)) + if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i)) spk_mask |= eld_speaker_allocation_bits[i]; } @@ -1743,7 +1743,7 @@ static void had_audio_wq(struct work_struct *work) break; } - memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld)); + memcpy(ctx->eld, eld->eld_data, sizeof(ctx->eld)); ctx->dp_output = pdata->dp_output; ctx->tmds_clock_speed = pdata->tmds_clock_speed; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 2804e94a6710..4ccaa8b18566 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -37,6 +37,7 @@ #include #include #include +#include #include "intel_hdmi_lpe_audio.h" #define PCM_INDEX 0 @@ -107,7 +108,7 @@ struct snd_intelhad { enum had_drv_status drv_status; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; - union otm_hdmi_eld_t eld; + unsigned char eld[HDMI_MAX_ELD_BYTES]; bool dp_output; enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 1e7e6db987c6..f9c184960b34 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -104,125 +104,6 @@ #define MAX_CNT 0xFF #define HAD_SUSPEND_DELAY 1000 -#define OTM_HDMI_ELD_SIZE 128 - -union otm_hdmi_eld_t { - unsigned char eld_data[OTM_HDMI_ELD_SIZE]; - struct { - /* Byte[0] = ELD Version Number */ - union { - unsigned char byte0; - struct { - unsigned char reserved:3; /* Reserf */ - unsigned char eld_ver:5; /* ELD Version Number */ - /* 00000b - reserved - * 00001b - first rev, obsoleted - * 00010b - version 2, supporting CEA version - * 861D or below - * 00011b:11111b - reserved - * for future - */ - }; - }; - - /* Byte[1] = Vendor Version Field */ - union { - unsigned char vendor_version; - struct { - unsigned char reserved1:3; - unsigned char veld_ver:5; /* Version number of the ELD - * extension. This value is - * provisioned and unique to - * each vendor. - */ - }; - }; - - /* Byte[2] = Baseline Length field */ - unsigned char baseline_eld_length; /* Length of the Baseline structure - * divided by Four. - */ - - /* Byte [3] = Reserved for future use */ - unsigned char byte3; - - /* Starting of the BaseLine EELD structure - * Byte[4] = Monitor Name Length - */ - union { - unsigned char byte4; - struct { - unsigned char mnl:5; - unsigned char cea_edid_rev_id:3; - }; - }; - - /* Byte[5] = Capabilities */ - union { - unsigned char capabilities; - struct { - unsigned char hdcp:1; /* HDCP support */ - unsigned char ai_support:1; /* AI support */ - unsigned char connection_type:2; /* Connection type - * 00 - HDMI - * 01 - DP - * 10 -11 Reserved - * for future - * connection types - */ - unsigned char sadc:4; /* Indicates number of 3 bytes - * Short Audio Descriptors. - */ - }; - }; - - /* Byte[6] = Audio Synch Delay */ - unsigned char audio_synch_delay; /* Amount of time reported by the - * sink that the video trails audio - * in milliseconds. - */ - - /* Byte[7] = Speaker Allocation Block */ - union { - unsigned char speaker_allocation_block; - struct { - unsigned char flr:1; /*Front Left and Right channels*/ - unsigned char lfe:1; /*Low Frequency Effect channel*/ - unsigned char fc:1; /*Center transmission channel*/ - unsigned char rlr:1; /*Rear Left and Right channels*/ - unsigned char rc:1; /*Rear Center channel*/ - unsigned char flrc:1; /*Front left and Right of Center - *transmission channels - */ - unsigned char rlrc:1; /*Rear left and Right of Center - *transmission channels - */ - unsigned char reserved3:1; /* Reserved */ - }; - }; - - /* Byte[8 - 15] - 8 Byte port identification value */ - unsigned char port_id_value[8]; - - /* Byte[16 - 17] - 2 Byte Manufacturer ID */ - unsigned char manufacturer_id[2]; - - /* Byte[18 - 19] - 2 Byte Product ID */ - unsigned char product_id[2]; - - /* Byte [20-83] - 64 Bytes of BaseLine Data */ - unsigned char mn_sand_sads[64]; /* This will include - * - ASCII string of Monitor name - * - List of 3 byte SADs - * - Zero padding - */ - - /* Vendor ELD Block should continue here! - * No Vendor ELD block defined as of now. - */ - } __packed; -}; - enum had_drv_status { HAD_DRV_CONNECTED, HAD_DRV_RUNNING, From 7ceba75f21e4ecb520b110ffada72cc0c9f5c072 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 15:58:35 +0100 Subject: [PATCH 48/54] ALSA: x86: Reduce redundant register field names Currently each register definition contains the own prefix in the union struct itself; for example, union aud_ch_status_0 has status_0_regx and status_0_regval fields. These are simply superfluous, since usually the type of the variable is seen in its declaration or in its name. In this patch, we cut off these prefixes. Now all register definitions have regx and regval fields consistently, instead. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 102 ++++++++++---------- sound/x86/intel_hdmi_audio.h | 1 - sound/x86/intel_hdmi_lpe_audio.h | 156 ++++++++----------------------- 3 files changed, 90 insertions(+), 169 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 496d3e92b2a8..f825d514500e 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -263,7 +263,7 @@ static void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata, bool enable) { - union aud_cfg cfg_val = {.cfg_regval = 0}; + union aud_cfg cfg_val = {.regval = 0}; u8 channels, data, mask; /* @@ -271,9 +271,9 @@ static void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, * In this case just set channels to 2 */ channels = substream ? substream->runtime->channels : 2; - cfg_val.cfg_regx.num_ch = channels - 2; + cfg_val.regx.num_ch = channels - 2; - data = cfg_val.cfg_regval; + data = cfg_val.regval; if (enable) data |= 1; mask = AUD_CONFIG_CH_MASK | 1; @@ -310,39 +310,39 @@ static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, static int had_prog_status_reg(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata) { - union aud_cfg cfg_val = {.cfg_regval = 0}; - union aud_ch_status_0 ch_stat0 = {.status_0_regval = 0}; - union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0}; + union aud_cfg cfg_val = {.regval = 0}; + union aud_ch_status_0 ch_stat0 = {.regval = 0}; + union aud_ch_status_1 ch_stat1 = {.regval = 0}; int format; - ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits & + ch_stat0.regx.lpcm_id = (intelhaddata->aes_bits & IEC958_AES0_NONAUDIO) >> 1; - ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & + ch_stat0.regx.clk_acc = (intelhaddata->aes_bits & IEC958_AES3_CON_CLOCK) >> 4; - cfg_val.cfg_regx.val_bit = ch_stat0.status_0_regx.lpcm_id; + cfg_val.regx.val_bit = ch_stat0.regx.lpcm_id; switch (substream->runtime->rate) { case AUD_SAMPLE_RATE_32: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_32KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_32KHZ; break; case AUD_SAMPLE_RATE_44_1: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_44KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_44KHZ; break; case AUD_SAMPLE_RATE_48: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_48KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_48KHZ; break; case AUD_SAMPLE_RATE_88_2: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_88KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_88KHZ; break; case AUD_SAMPLE_RATE_96: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_96KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_96KHZ; break; case AUD_SAMPLE_RATE_176_4: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_176KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_176KHZ; break; case AUD_SAMPLE_RATE_192: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_192KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_192KHZ; break; default: @@ -351,23 +351,23 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, } had_write_register(intelhaddata, - AUD_CH_STATUS_0, ch_stat0.status_0_regval); + AUD_CH_STATUS_0, ch_stat0.regval); format = substream->runtime->format; if (format == SNDRV_PCM_FORMAT_S16_LE) { - ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_20; - ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_16BITS; + ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_20; + ch_stat1.regx.wrd_len = SMPL_WIDTH_16BITS; } else if (format == SNDRV_PCM_FORMAT_S24_LE) { - ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_24; - ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_24BITS; + ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_24; + ch_stat1.regx.wrd_len = SMPL_WIDTH_24BITS; } else { - ch_stat1.status_1_regx.max_wrd_len = 0; - ch_stat1.status_1_regx.wrd_len = 0; + ch_stat1.regx.max_wrd_len = 0; + ch_stat1.regx.wrd_len = 0; } had_write_register(intelhaddata, - AUD_CH_STATUS_1, ch_stat1.status_1_regval); + AUD_CH_STATUS_1, ch_stat1.regval); return 0; } @@ -379,26 +379,26 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata) { - union aud_cfg cfg_val = {.cfg_regval = 0}; - union aud_buf_config buf_cfg = {.buf_cfgval = 0}; + union aud_cfg cfg_val = {.regval = 0}; + union aud_buf_config buf_cfg = {.regval = 0}; u8 channels; had_prog_status_reg(substream, intelhaddata); - buf_cfg.buf_cfg_regx.audio_fifo_watermark = FIFO_THRESHOLD; - buf_cfg.buf_cfg_regx.dma_fifo_watermark = DMA_FIFO_THRESHOLD; - buf_cfg.buf_cfg_regx.aud_delay = 0; - had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.buf_cfgval); + buf_cfg.regx.audio_fifo_watermark = FIFO_THRESHOLD; + buf_cfg.regx.dma_fifo_watermark = DMA_FIFO_THRESHOLD; + buf_cfg.regx.aud_delay = 0; + had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.regval); channels = substream->runtime->channels; - cfg_val.cfg_regx.num_ch = channels - 2; + cfg_val.regx.num_ch = channels - 2; if (channels <= 2) - cfg_val.cfg_regx.layout = LAYOUT0; + cfg_val.regx.layout = LAYOUT0; else - cfg_val.cfg_regx.layout = LAYOUT1; + cfg_val.regx.layout = LAYOUT1; - cfg_val.cfg_regx.val_bit = 1; - had_write_register(intelhaddata, AUD_CONFIG, cfg_val.cfg_regval); + cfg_val.regx.val_bit = 1; + had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval); return 0; } @@ -618,49 +618,49 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata) { int i; - union aud_ctrl_st ctrl_state = {.ctrl_val = 0}; - union aud_info_frame2 frame2 = {.fr2_val = 0}; - union aud_info_frame3 frame3 = {.fr3_val = 0}; + union aud_ctrl_st ctrl_state = {.regval = 0}; + union aud_info_frame2 frame2 = {.regval = 0}; + union aud_info_frame3 frame3 = {.regval = 0}; u8 checksum = 0; u32 info_frame; int channels; channels = substream->runtime->channels; - had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.ctrl_val); + had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval); if (intelhaddata->dp_output) { info_frame = DP_INFO_FRAME_WORD1; - frame2.fr2_val = 1; + frame2.regval = 1; } else { info_frame = HDMI_INFO_FRAME_WORD1; - frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1; + frame2.regx.chnl_cnt = substream->runtime->channels - 1; - frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation( + frame3.regx.chnl_alloc = snd_intelhad_channel_allocation( intelhaddata, channels); /* Calculte the byte wide checksum for all valid DIP words */ for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (info_frame >> i*BITS_PER_BYTE) & MASK_BYTE0; + checksum += (info_frame >> (i * 8)) & 0xff; for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0; + checksum += (frame2.regval >> (i * 8)) & 0xff; for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0; + checksum += (frame3.regval >> (i * 8)) & 0xff; - frame2.fr2_regx.chksum = -(checksum); + frame2.regx.chksum = -(checksum); } had_write_register(intelhaddata, AUD_HDMIW_INFOFR, info_frame); - had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame2.fr2_val); - had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame3.fr3_val); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame2.regval); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame3.regval); /* program remaining DIP words with zero */ for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++) had_write_register(intelhaddata, AUD_HDMIW_INFOFR, 0x0); - ctrl_state.ctrl_regx.dip_freq = 1; - ctrl_state.ctrl_regx.dip_en_sta = 1; - had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.ctrl_val); + ctrl_state.regx.dip_freq = 1; + ctrl_state.regx.dip_en_sta = 1; + had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval); } /* diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 4ccaa8b18566..9dc0da474f05 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -65,7 +65,6 @@ #define SMPL_WIDTH_16BITS 0x1 #define SMPL_WIDTH_24BITS 0x5 #define CHANNEL_ALLOCATION 0x1F -#define MASK_BYTE0 0x000000FF #define VALID_DIP_WORDS 3 #define LAYOUT0 0 #define LAYOUT1 1 diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index f9c184960b34..0e8397970e4a 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -199,13 +199,7 @@ struct channel_map_table { int spk_mask; /* speaker position bit mask */ }; -/** - * union aud_cfg - Audio configuration - * - * @cfg_regx: individual register bits - * @cfg_regval: full register value - * - */ +/* Audio configuration */ union aud_cfg { struct { u32 aud_en:1; @@ -222,17 +216,11 @@ union aud_cfg { u32 bogus_sample:1; u32 dp_modei:1; u32 rsvd:16; - } cfg_regx; - u32 cfg_regval; + } regx; + u32 regval; }; -/** - * union aud_ch_status_0 - Audio Channel Status 0 Attributes - * - * @status_0_regx:individual register bits - * @status_0_regval:full register value - * - */ +/* Audio Channel Status 0 Attributes */ union aud_ch_status_0 { struct { u32 ch_status:1; @@ -246,65 +234,41 @@ union aud_ch_status_0 { u32 samp_freq:4; u32 clk_acc:2; u32 rsvd:2; - } status_0_regx; - u32 status_0_regval; + } regx; + u32 regval; }; -/** - * union aud_ch_status_1 - Audio Channel Status 1 Attributes - * - * @status_1_regx: individual register bits - * @status_1_regval: full register value - * - */ +/* Audio Channel Status 1 Attributes */ union aud_ch_status_1 { struct { u32 max_wrd_len:1; u32 wrd_len:3; u32 rsvd:28; - } status_1_regx; - u32 status_1_regval; + } regx; + u32 regval; }; -/** - * union aud_hdmi_cts - CTS register - * - * @cts_regx: individual register bits - * @cts_regval: full register value - * - */ +/* CTS register */ union aud_hdmi_cts { struct { u32 cts_val:24; u32 en_cts_prog:1; u32 rsvd:7; - } cts_regx; - u32 cts_regval; + } regx; + u32 regval; }; -/** - * union aud_hdmi_n_enable - N register - * - * @n_regx: individual register bits - * @n_regval: full register value - * - */ +/* N register */ union aud_hdmi_n_enable { struct { u32 n_val:24; u32 en_n_prog:1; u32 rsvd:7; - } n_regx; - u32 n_regval; + } regx; + u32 regval; }; -/** - * union aud_buf_config - Audio Buffer configurations - * - * @buf_cfg_regx: individual register bits - * @buf_cfgval: full register value - * - */ +/* Audio Buffer configurations */ union aud_buf_config { struct { u32 audio_fifo_watermark:8; @@ -312,17 +276,11 @@ union aud_buf_config { u32 rsvd0:5; u32 aud_delay:8; u32 rsvd1:8; - } buf_cfg_regx; - u32 buf_cfgval; + } regx; + u32 regval; }; -/** - * union aud_buf_ch_swap - Audio Sample Swapping offset - * - * @buf_ch_swap_regx: individual register bits - * @buf_ch_swap_val: full register value - * - */ +/* Audio Sample Swapping offset */ union aud_buf_ch_swap { struct { u32 first_0:3; @@ -334,49 +292,31 @@ union aud_buf_ch_swap { u32 first_3:3; u32 second_3:3; u32 rsvd:8; - } buf_ch_swap_regx; - u32 buf_ch_swap_val; + } regx; + u32 regval; }; -/** - * union aud_buf_addr - Address for Audio Buffer - * - * @buf_addr_regx: individual register bits - * @buf_addr_val: full register value - * - */ +/* Address for Audio Buffer */ union aud_buf_addr { struct { u32 valid:1; u32 intr_en:1; u32 rsvd:4; u32 addr:26; - } buf_addr_regx; - u32 buf_addr_val; + } regx; + u32 regval; }; -/** - * union aud_buf_len - Length of Audio Buffer - * - * @buf_len_regx: individual register bits - * @buf_len_val: full register value - * - */ +/* Length of Audio Buffer */ union aud_buf_len { struct { u32 buf_len:20; u32 rsvd:12; - } buf_len_regx; - u32 buf_len_val; + } regx; + u32 regval; }; -/** - * union aud_ctrl_st - Audio Control State Register offset - * - * @ctrl_regx: individual register bits - * @ctrl_val: full register value - * - */ +/* Audio Control State Register offset */ union aud_ctrl_st { struct { u32 ram_addr:4; @@ -389,34 +329,22 @@ union aud_ctrl_st { u32 dip_idx:3; u32 dip_en_sta:4; u32 rsvd:7; - } ctrl_regx; - u32 ctrl_val; + } regx; + u32 regval; }; -/** - * union aud_info_frame1 - Audio HDMI Widget Data Island Packet offset - * - * @fr1_regx: individual register bits - * @fr1_val: full register value - * - */ +/* Audio HDMI Widget Data Island Packet offset */ union aud_info_frame1 { struct { u32 pkt_type:8; u32 ver_num:8; u32 len:5; u32 rsvd:11; - } fr1_regx; - u32 fr1_val; + } regx; + u32 regval; }; -/** - * union aud_info_frame2 - DIP frame 2 - * - * @fr2_regx: individual register bits - * @fr2_val: full register value - * - */ +/* DIP frame 2 */ union aud_info_frame2 { struct { u32 chksum:8; @@ -427,17 +355,11 @@ union aud_info_frame2 { u32 smpl_freq:3; u32 rsvd1:3; u32 format:8; - } fr2_regx; - u32 fr2_val; + } regx; + u32 regval; }; -/** - * union aud_info_frame3 - DIP frame 3 - * - * @fr3_regx: individual register bits - * @fr3_val: full register value - * - */ +/* DIP frame 3 */ union aud_info_frame3 { struct { u32 chnl_alloc:8; @@ -445,8 +367,8 @@ union aud_info_frame3 { u32 lsv:4; u32 dm_inh:1; u32 rsvd1:16; - } fr3_regx; - u32 fr3_val; + } regx; + u32 regval; }; #define HDMI_AUDIO_UNDERRUN (1UL<<31) From 03c3437755881a9f6f1b5f8c05e62edf7898a87f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 16:19:03 +0100 Subject: [PATCH 49/54] ALSA: x86: Clean up unused defines and inclusions Many defines and constants are left unused. Clean them up. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 10 +++-- sound/x86/intel_hdmi_audio.h | 11 +----- sound/x86/intel_hdmi_lpe_audio.h | 68 ++++++-------------------------- 3 files changed, 20 insertions(+), 69 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index f825d514500e..82f48fbcd74b 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -21,19 +21,21 @@ * ALSA driver for Intel HDMI audio */ +#include #include #include #include #include #include -#include +#include #include -#include #include +#include +#include #include #include #include -#include +#include #include #include "intel_hdmi_audio.h" @@ -929,6 +931,8 @@ static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, return 0; } +#define MAX_CNT 0xFF + static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) { u32 hdmi_status = 0, i = 0; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 9dc0da474f05..dea51fcfc07f 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -30,20 +30,11 @@ #ifndef _INTEL_HDMI_AUDIO_H_ #define _INTEL_HDMI_AUDIO_H_ -#include -#include -#include -#include -#include -#include -#include -#include #include "intel_hdmi_lpe_audio.h" #define PCM_INDEX 0 #define MAX_PB_STREAMS 1 #define MAX_CAP_STREAMS 0 -#define HDMI_AUDIO_DRIVER "hdmi-audio" #define HDMI_INFO_FRAME_WORD1 0x000a0184 #define DP_INFO_FRAME_WORD1 0x00441b84 @@ -85,7 +76,7 @@ struct ring_buf_info { u8 is_valid; }; -/** +/* * struct snd_intelhad - intelhad driver structure * * @card: ptr to hold card details diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 0e8397970e4a..5a5adb7f0cde 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -23,20 +23,6 @@ #ifndef __INTEL_HDMI_LPE_AUDIO_H #define __INTEL_HDMI_LPE_AUDIO_H -#include -#include -#include -#include -#include -#include -#include -#include - -#define AUD_CONFIG_VALID_BIT (1<<9) -#define AUD_CONFIG_DP_MODE (1<<15) -#define AUD_CONFIG_BLOCK_BIT (1<<7) - -#define HMDI_LPE_AUDIO_DRIVER_NAME "intel-hdmi-lpe-audio" #define HAD_MAX_DEVICES 1 #define HAD_MIN_CHANNEL 2 #define HAD_MAX_CHANNEL 8 @@ -96,14 +82,6 @@ /* Naud Value */ #define DP_NAUD_VAL 32768 -/* _AUD_CONFIG register MASK */ -#define AUD_CONFIG_MASK_UNDERRUN 0xC0000000 -#define AUD_CONFIG_MASK_SRDBG 0x00000002 -#define AUD_CONFIG_MASK_FUNCRST 0x00000001 - -#define MAX_CNT 0xFF -#define HAD_SUSPEND_DELAY 1000 - enum had_drv_status { HAD_DRV_CONNECTED, HAD_DRV_RUNNING, @@ -120,17 +98,10 @@ enum intel_had_aud_buf_type { HAD_BUF_TYPE_D = 3, }; -enum num_aud_ch { - CH_STEREO = 0, - CH_THREE_FOUR = 1, - CH_FIVE_SIX = 2, - CH_SEVEN_EIGHT = 3 -}; - /* HDMI Controller register offsets - audio domain common */ /* Base address for below regs = 0x65000 */ enum hdmi_ctrl_reg_offset_common { - AUDIO_HDMI_CONFIG_A = 0x000, + AUDIO_HDMI_CONFIG_A = 0x000, AUDIO_HDMI_CONFIG_B = 0x800, AUDIO_HDMI_CONFIG_C = 0x900, }; @@ -220,6 +191,10 @@ union aud_cfg { u32 regval; }; +#define AUD_CONFIG_BLOCK_BIT (1 << 7) +#define AUD_CONFIG_VALID_BIT (1 << 9) +#define AUD_CONFIG_DP_MODE (1 << 15) + /* Audio Channel Status 0 Attributes */ union aud_ch_status_0 { struct { @@ -371,32 +346,13 @@ union aud_info_frame3 { u32 regval; }; -#define HDMI_AUDIO_UNDERRUN (1UL<<31) -#define HDMI_AUDIO_BUFFER_DONE (1UL<<29) +/* AUD_HDMI_STATUS bits */ +#define HDMI_AUDIO_UNDERRUN (1U << 31) +#define HDMI_AUDIO_BUFFER_DONE (1U << 29) - -#define PORT_ENABLE (1 << 31) -#define SDVO_AUDIO_ENABLE (1 << 6) - -enum had_caps_list { - HAD_GET_ELD = 1, - HAD_GET_DISPLAY_RATE, - HAD_GET_DP_OUTPUT, - HAD_GET_LINK_RATE, - HAD_SET_ENABLE_AUDIO, - HAD_SET_DISABLE_AUDIO, - HAD_SET_ENABLE_AUDIO_INT, - HAD_SET_DISABLE_AUDIO_INT, -}; - -enum had_event_type { - HAD_EVENT_HOT_PLUG = 1, - HAD_EVENT_HOT_UNPLUG, - HAD_EVENT_MODE_CHANGING, - HAD_EVENT_AUDIO_BUFFER_DONE, - HAD_EVENT_AUDIO_BUFFER_UNDERRUN, - HAD_EVENT_QUERY_IS_AUDIO_BUSY, - HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED, -}; +/* AUD_HDMI_STATUS register mask */ +#define AUD_CONFIG_MASK_UNDERRUN 0xC0000000 +#define AUD_CONFIG_MASK_SRDBG 0x00000002 +#define AUD_CONFIG_MASK_FUNCRST 0x00000001 #endif From 4aedb9465f717a8393bb5f40581eb7942af12506 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 16:38:39 +0100 Subject: [PATCH 50/54] ALSA: x86: Create ELD control element Like other drivers, expose the ELD bytes via a control element so that user-space can parse it. For the simplicity, the code to register the ctl elements is refactored using an array. Also, since ELD ctl read copies the bytes also during disconnection, clear the ELD bytes at hot-unplug, in order to avoid the leak of the previous bogus ELD. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 72 +++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 82f48fbcd74b..f49520117dd6 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1669,21 +1669,51 @@ static int had_iec958_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new had_control_iec958_mask = { - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), - .info = had_iec958_info, /* shared */ - .get = had_iec958_mask_get, +static int had_ctl_eld_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = HDMI_MAX_ELD_BYTES; + return 0; +} + +static int had_ctl_eld_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); + + mutex_lock(&intelhaddata->mutex); + memcpy(ucontrol->value.bytes.data, intelhaddata->eld, + HDMI_MAX_ELD_BYTES); + mutex_unlock(&intelhaddata->mutex); + return 0; +} + +static struct snd_kcontrol_new had_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), + .info = had_iec958_info, /* shared */ + .get = had_iec958_mask_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = had_iec958_info, + .get = had_iec958_get, + .put = had_iec958_put, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "ELD", + .info = had_ctl_eld_info, + .get = had_ctl_eld_get, + }, }; -static struct snd_kcontrol_new had_control_iec958 = { - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), - .info = had_iec958_info, - .get = had_iec958_get, - .put = had_iec958_put -}; static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { @@ -1724,6 +1754,7 @@ static void had_audio_wq(struct work_struct *work) if (!pdata->hdmi_connected) { dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", __func__); + memset(ctx->eld, 0, sizeof(ctx->eld)); /* clear the old ELD */ had_process_hot_unplug(ctx); } else { struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; @@ -1826,7 +1857,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) struct intel_hdmi_lpe_audio_pdata *pdata; int irq; struct resource *res_mmio; - int ret; + int i, ret; dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); @@ -1918,13 +1949,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) SNDRV_DMA_TYPE_DEV, NULL, HAD_MAX_BUFFER, HAD_MAX_BUFFER); - /* IEC958 controls */ - ret = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask, ctx)); - if (ret < 0) - goto err; - ret = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958, ctx)); - if (ret < 0) - goto err; + /* create controls */ + for (i = 0; i < ARRAY_SIZE(had_controls); i++) { + ret = snd_ctl_add(card, snd_ctl_new1(&had_controls[i], ctx)); + if (ret < 0) + goto err; + } init_channel_allocations(); From 36ed34662f1944ebf553b30fcba1abab1703d125 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 17:06:38 +0100 Subject: [PATCH 51/54] ALSA: x86: Set CA bits for DisplayPort too This is a guess work. Usually the DP audio info frame is just 8-bit shifted from HDMI AI, so let's try to put CA in DIP frame 2 [24-31]. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index f49520117dd6..24a18b88c927 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -626,20 +626,20 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, u8 checksum = 0; u32 info_frame; int channels; + int ca; channels = substream->runtime->channels; had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval); + ca = snd_intelhad_channel_allocation(intelhaddata, channels); if (intelhaddata->dp_output) { info_frame = DP_INFO_FRAME_WORD1; - frame2.regval = 1; + frame2.regval = (substream->runtime->channels - 1) | (ca << 24); } else { info_frame = HDMI_INFO_FRAME_WORD1; frame2.regx.chnl_cnt = substream->runtime->channels - 1; - - frame3.regx.chnl_alloc = snd_intelhad_channel_allocation( - intelhaddata, channels); + frame3.regx.chnl_alloc = ca; /* Calculte the byte wide checksum for all valid DIP words */ for (i = 0; i < BYTES_PER_WORD; i++) From 44684f61b23c68786834dd2a99d4a68d40a13308 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 17:27:40 +0100 Subject: [PATCH 52/54] ALSA: x86: Simplify comments It's a stand-alone small driver code, and we don't have to describe too much formalized comments in kernel-doc style for local functions at all. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 66 ++++++++---------------------------- 1 file changed, 14 insertions(+), 52 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 24a18b88c927..5613c675ce70 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -609,11 +609,7 @@ static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, } /* - * snd_intelhad_prog_dip - to initialize Data Island Packets registers - * - * @substream:substream for which the prepare function is called - * @intelhaddata:substream private data - * + * Initialize Data Island Packets registers * This function is called in the prepare callback */ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, @@ -666,10 +662,7 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, } /* - * snd_intelhad_prog_buffer - programs buffer address and length registers - * @substream: substream for which the prepare function is called - * @intelhaddata: substream private data - * + * Programs buffer address and length registers * This function programs ring buffer address and length into registers. */ static int snd_intelhad_prog_buffer(struct snd_pcm_substream *substream, @@ -824,7 +817,7 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) } /* - * snd_intelhad_prog_cts - Program HDMI audio CTS value + * Program HDMI audio CTS value * * @aud_samp_freq: sampling frequency of audio data * @tmds: sampling frequency of the display data @@ -896,7 +889,7 @@ static int had_calculate_n_value(u32 aud_samp_freq) } /* - * snd_intelhad_prog_n - Program HDMI audio N value + * Program HDMI audio N value * * @aud_samp_freq: sampling frequency of audio data * @n_param: N value, depends on aud_samp_freq @@ -962,10 +955,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) } /* - * snd_intelhad_open - stream initializations are done here - * @substream:substream for which the stream function is called - * - * This function is called whenever a PCM stream is opened + * ALSA PCM open callback */ static int snd_intelhad_open(struct snd_pcm_substream *substream) { @@ -1017,10 +1007,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) } /* - * snd_intelhad_close - to free parameteres when stream is stopped - * @substream: substream for which the function is called - * - * This function is called by ALSA framework when stream is stopped + * ALSA PCM close callback */ static int snd_intelhad_close(struct snd_pcm_substream *substream) { @@ -1051,12 +1038,7 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) } /* - * snd_intelhad_hw_params - to setup the hardware parameters - * like allocating the buffers - * @substream: substream for which the function is called - * @hw_params: hardware parameters - * - * This function is called by ALSA framework when hardware params are set + * ALSA PCM hw_params callback */ static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) @@ -1090,11 +1072,7 @@ static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, } /* - * snd_intelhad_hw_free - to release the resources allocated during - * hardware params setup - * @substream: substream for which the function is called - * - * This function is called by ALSA framework before close callback. + * ALSA PCM hw_free callback */ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) { @@ -1113,11 +1091,7 @@ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) } /* - * snd_intelhad_pcm_trigger - stream activities are handled here - * @substream: substream for which the stream function is called - * @cmd: the stream commamd thats requested from upper layer - * - * This function is called whenever an a stream activity is invoked + * ALSA PCM trigger callback */ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, int cmd) @@ -1172,10 +1146,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, } /* - * snd_intelhad_pcm_prepare - internal preparation before starting a stream - * @substream: substream for which the function is called - * - * This function is called when a stream is started for internal preparation. + * ALSA PCM prepare callback */ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) { @@ -1243,14 +1214,10 @@ prep_end: } /* - * snd_intelhad_pcm_pointer- to send the current buffer pointerprocessed by hw - * @substream: substream for which the function is called - * - * This function is called by ALSA framework to get the current hw buffer ptr - * when a period is elapsed + * ALSA PCM pointer callback */ -static snd_pcm_uframes_t snd_intelhad_pcm_pointer( - struct snd_pcm_substream *substream) +static snd_pcm_uframes_t +snd_intelhad_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; u32 bytes_rendered = 0; @@ -1299,12 +1266,7 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( } /* - * snd_intelhad_pcm_mmap- mmaps a kernel buffer to user space for copying data - * @substream: substream for which the function is called - * @vma: struct instance of memory VMM memory area - * - * This function is called by OS when a user space component - * tries to get mmap memory from driver + * ALSA PCM mmap callback */ static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) From 73997b050c995f34f3617d344f1e767d15b2477d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 17:38:50 +0100 Subject: [PATCH 53/54] ALSA: x86: Yet more tidy-up and clean-ups - Add a few more comments to functions. - Move the initialization of some PCM state variables to open and prepare callbacks, where these are clearer places. - Remove superfluous NULL checks. - Get rid of the bogus drv_status change to CONNECTED at close; this doesn't make any sense. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 68 +++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 5613c675ce70..f032610d1287 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -965,7 +965,6 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - intelhaddata->underrun_count = 0; pm_runtime_get_sync(intelhaddata->dev); @@ -989,17 +988,20 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) */ retval = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); - if (retval < 0) { - dev_dbg(intelhaddata->dev, "%s:step_size=64 failed,err=%d\n", - __func__, retval); + if (retval < 0) goto error; - } + /* expose PCM substream */ spin_lock_irq(&intelhaddata->had_spinlock); intelhaddata->stream_info.substream = substream; intelhaddata->stream_info.substream_refcount++; spin_unlock_irq(&intelhaddata->had_spinlock); + /* these are cleared in prepare callback, but just to be sure */ + intelhaddata->curr_buf = 0; + intelhaddata->underrun_count = 0; + intelhaddata->stream_info.buffer_rendered = 0; + return retval; error: pm_runtime_put(intelhaddata->dev); @@ -1015,7 +1017,7 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); - intelhaddata->stream_info.buffer_rendered = 0; + /* unreference and sync with the pending PCM accesses */ spin_lock_irq(&intelhaddata->had_spinlock); intelhaddata->stream_info.substream = NULL; intelhaddata->stream_info.substream_refcount--; @@ -1026,13 +1028,6 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) } spin_unlock_irq(&intelhaddata->had_spinlock); - /* Check if following drv_status modification is required - VA */ - if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { - intelhaddata->drv_status = HAD_DRV_CONNECTED; - dev_dbg(intelhaddata->dev, - "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", - __func__, __LINE__); - } pm_runtime_put(intelhaddata->dev); return 0; } @@ -1047,9 +1042,6 @@ static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, unsigned long addr; int pages, buf_size, retval; - if (!hw_params) - return -EINVAL; - intelhaddata = snd_pcm_substream_chip(substream); buf_size = params_buffer_bytes(hw_params); retval = snd_pcm_lib_malloc_pages(substream, buf_size); @@ -1124,7 +1116,6 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: spin_lock(&intelhaddata->had_spinlock); - intelhaddata->curr_buf = 0; /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ @@ -1174,6 +1165,8 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate); dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels); + intelhaddata->curr_buf = 0; + intelhaddata->underrun_count = 0; intelhaddata->stream_info.buffer_rendered = 0; /* Get N value in KHz */ @@ -1247,7 +1240,6 @@ snd_intelhad_pcm_pointer(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "assume audio_codec_reset, underrun = %d - do xrun\n", intelhaddata->underrun_count); - intelhaddata->underrun_count = 0; return SNDRV_PCM_POS_XRUN; } } else { @@ -1277,6 +1269,21 @@ static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, vma->vm_end - vma->vm_start, vma->vm_page_prot); } +/* + * ALSA PCM ops + */ +static const struct snd_pcm_ops snd_intelhad_playback_ops = { + .open = snd_intelhad_open, + .close = snd_intelhad_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_intelhad_hw_params, + .hw_free = snd_intelhad_hw_free, + .prepare = snd_intelhad_pcm_prepare, + .trigger = snd_intelhad_pcm_trigger, + .pointer = snd_intelhad_pcm_pointer, + .mmap = snd_intelhad_pcm_mmap, +}; + /* process mode change of the running stream; called in mutex */ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) { @@ -1564,18 +1571,9 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) intelhaddata->chmap->chmap = NULL; } -/* PCM operations structure and the calls back for the same */ -static struct snd_pcm_ops snd_intelhad_playback_ops = { - .open = snd_intelhad_open, - .close = snd_intelhad_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_intelhad_hw_params, - .hw_free = snd_intelhad_hw_free, - .prepare = snd_intelhad_pcm_prepare, - .trigger = snd_intelhad_pcm_trigger, - .pointer = snd_intelhad_pcm_pointer, - .mmap = snd_intelhad_pcm_mmap, -}; +/* + * ALSA iec958 and ELD controls + */ static int had_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -1651,7 +1649,7 @@ static int had_ctl_eld_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new had_controls[] = { +static const struct snd_kcontrol_new had_controls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1676,7 +1674,9 @@ static struct snd_kcontrol_new had_controls[] = { }, }; - +/* + * audio interrupt handler + */ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { struct snd_intelhad *ctx = dev_id; @@ -1698,6 +1698,9 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * monitor plug/unplug notification from i915; just kick off the work + */ static void notify_audio_lpe(struct platform_device *pdev) { struct snd_intelhad *ctx = platform_get_drvdata(pdev); @@ -1705,6 +1708,7 @@ static void notify_audio_lpe(struct platform_device *pdev) schedule_work(&ctx->hdmi_audio_wq); } +/* the work to handle monitor hot plug/unplug */ static void had_audio_wq(struct work_struct *work) { struct snd_intelhad *ctx = From 91b0cb0cc07bcb5114df2897531f4ea41c148c8e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 17:46:49 +0100 Subject: [PATCH 54/54] ALSA: x86: Rename drv_status to connected After the rewrite of the runtime PM code, we have only two driver status: CONNECTED and DISCONNECTED. So it's clearer to use a boolean flag, and name it easier one, "connected". Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 40 ++++++++++++++++---------------- sound/x86/intel_hdmi_audio.h | 4 ++-- sound/x86/intel_hdmi_lpe_audio.h | 8 ------- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index f032610d1287..c83f02c2593e 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -202,7 +202,7 @@ mid_hdmi_audio_write(struct snd_intelhad *ctx, u32 reg, u32 val) static int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) { - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return -ENODEV; mid_hdmi_audio_read(intelhaddata, offset, data); @@ -221,7 +221,7 @@ static void fixup_dp_config(struct snd_intelhad *intelhaddata, static int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) { - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return -ENODEV; fixup_dp_config(intelhaddata, offset, &data); @@ -234,7 +234,7 @@ static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, { u32 val_tmp; - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return -ENODEV; mid_hdmi_audio_read(intelhaddata, offset, &val_tmp); @@ -556,7 +556,7 @@ static int had_chmap_ctl_info(struct snd_kcontrol *kcontrol, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct snd_intelhad *intelhaddata = info->private_data; - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return -ENODEV; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = HAD_MAX_CHANNEL; @@ -573,7 +573,7 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, int i; const struct snd_pcm_chmap_elem *chmap; - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return -ENODEV; mutex_lock(&intelhaddata->mutex); @@ -968,7 +968,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) pm_runtime_get_sync(intelhaddata->dev); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", __func__); retval = -ENODEV; @@ -1098,7 +1098,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: /* Disable local INTRs till register prgmng is done */ - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "_START: HDMI cable plugged-out\n"); retval = -ENODEV; @@ -1150,7 +1150,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", __func__); retval = -ENODEV; @@ -1219,7 +1219,7 @@ snd_intelhad_pcm_pointer(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return SNDRV_PCM_POS_XRUN; /* Use a hw register to calculate sub-period position reports. @@ -1380,7 +1380,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) intr_count = 1; spin_lock_irqsave(&intelhaddata->had_spinlock, flags); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); dev_dbg(intelhaddata->dev, "%s:Device already disconnected\n", __func__); @@ -1419,7 +1419,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "HDMI cable plugged-out\n"); return 0; } @@ -1460,14 +1460,14 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) struct pcm_stream_info *stream; struct snd_pcm_substream *substream; unsigned long flags; - int drv_status; + int connected; stream = &intelhaddata->stream_info; spin_lock_irqsave(&intelhaddata->had_spinlock, flags); buf_id = intelhaddata->curr_buf; intelhaddata->buff_done = buf_id; - drv_status = intelhaddata->drv_status; + connected = intelhaddata->connected; if (stream->running) intelhaddata->curr_buf = HAD_BUF_TYPE_A; @@ -1478,7 +1478,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) snd_intelhad_handle_underrun(intelhaddata); - if (drv_status == HAD_DRV_DISCONNECTED) { + if (!connected) { dev_dbg(intelhaddata->dev, "%s:Device already disconnected\n", __func__); return 0; @@ -1501,7 +1501,7 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) struct snd_pcm_substream *substream; spin_lock_irq(&intelhaddata->had_spinlock); - if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { + if (intelhaddata->connected) { dev_dbg(intelhaddata->dev, "Device already connected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); return; @@ -1509,7 +1509,7 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) buf_id = intelhaddata->curr_buf; intelhaddata->buff_done = buf_id; - intelhaddata->drv_status = HAD_DRV_CONNECTED; + intelhaddata->connected = true; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); @@ -1543,7 +1543,7 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) spin_lock_irq(&intelhaddata->had_spinlock); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "Device already disconnected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); goto out; @@ -1554,7 +1554,7 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) snd_intelhad_enable_audio_int(intelhaddata, false); snd_intelhad_enable_audio(substream, intelhaddata, false); - intelhaddata->drv_status = HAD_DRV_DISCONNECTED; + intelhaddata->connected = false; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); @@ -1855,7 +1855,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx = card->private_data; spin_lock_init(&ctx->had_spinlock); mutex_init(&ctx->mutex); - ctx->drv_status = HAD_DRV_DISCONNECTED; + ctx->connected = false; ctx->dev = &pdev->dev; ctx->card = card; ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; @@ -1960,7 +1960,7 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { struct snd_intelhad *ctx = platform_get_drvdata(pdev); - if (ctx->drv_status != HAD_DRV_DISCONNECTED) + if (ctx->connected) snd_intelhad_enable_audio_int(ctx, false); snd_card_free(ctx->card); return 0; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index dea51fcfc07f..9f713a8a88bc 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -80,7 +80,7 @@ struct ring_buf_info { * struct snd_intelhad - intelhad driver structure * * @card: ptr to hold card details - * @drv_status: driver status + * @connected: the monitor connection status * @buf_info: ring buffer info * @stream_info: stream information * @eld: holds ELD info @@ -95,7 +95,7 @@ struct ring_buf_info { */ struct snd_intelhad { struct snd_card *card; - enum had_drv_status drv_status; + bool connected; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; unsigned char eld[HDMI_MAX_ELD_BYTES]; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 5a5adb7f0cde..be9783910a3a 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -82,14 +82,6 @@ /* Naud Value */ #define DP_NAUD_VAL 32768 -enum had_drv_status { - HAD_DRV_CONNECTED, - HAD_DRV_RUNNING, - HAD_DRV_DISCONNECTED, - HAD_DRV_SUSPENDED, - HAD_DRV_ERR, -}; - /* enum intel_had_aud_buf_type - HDMI controller ring buffer types */ enum intel_had_aud_buf_type { HAD_BUF_TYPE_A = 0,