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; unsigned long flag_irqs; pr_debug("Enter:%s", __func__); had_stream = intelhaddata->private_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 retval; } 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); intelhaddata->ops->enable_audio(intelhaddata->stream_info.had_substream, 0); } intelhaddata->drv_status = HAD_DRV_DISCONNECTED; /* 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__); mutex_lock(&had_mutex); if (intelhaddata->stream_info.had_substream != NULL) snd_pcm_stop(intelhaddata->stream_info.had_substream, SNDRV_PCM_STATE_DISCONNECTED); mutex_unlock(&had_mutex); 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; pr_debug("%s: unlocked -> returned\n", __func__); return retval; }
/** * 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, hdmi_audio_event_t event) { int caps, retval = 0; struct had_pvt_data *had_stream; unsigned long flag_irqs; struct snd_pcm_substream *substream; struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; pr_debug("Enter:%s", __func__); had_stream = intelhaddata->private_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 retval; } if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); pr_debug("had already suspended\n"); return retval; } intelhaddata->drv_status = HAD_DRV_SUSPENDED; 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(HAD_SET_DISABLE_AUDIO_INT, &caps); had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); pr_debug("Exit:%s", __func__); return retval; }
/** * hdmi_audio_remove - removes the alsa card * *@haddata: pointer to HAD private data * * This function is called when the hdmi cable is un-plugged. This function * free the sound card. */ static int __devexit hdmi_audio_remove(struct platform_device *devptr) { struct snd_intelhad *intelhaddata = had_data; int caps; pr_debug("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(HAD_SET_DISABLE_AUDIO_INT, &caps); had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); } kfree(intelhaddata->flat_data); snd_card_free(intelhaddata->card); kfree(intelhaddata->private_data); kfree(intelhaddata); return 0; }
/** * hdmi_audio_resume - power management resume function * *@haddata: pointer to HAD private data * * This function is called by client driver to resume the * hdmi audio. */ int hdmi_audio_resume(void *haddata) { int caps, retval = 0; struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; unsigned long flag_irqs; pr_debug("Enter:%s", __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 (HAD_DRV_SUSPENDED != intelhaddata->drv_status) { 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; 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(HAD_SET_ENABLE_AUDIO_INT, &caps); retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL); pr_debug("Exit:%s", __func__); return retval; }
/** * 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 */ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { int caps, retval = 0; unsigned long flag_irq; struct snd_intelhad *intelhaddata; struct had_stream_pvt *stream; struct had_pvt_data *had_stream; intelhaddata = snd_pcm_substream_chip(substream); stream = substream->runtime->private_data; had_stream = intelhaddata->private_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"); retval = -ENODEV; break; } stream->stream_status = STREAM_RUNNING; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irq); had_stream->stream_type = HAD_RUNNING_STREAM; spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq); /* 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(HAD_SET_ENABLE_AUDIO_INT, &caps); retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL); had_read_modify(AUD_CONFIG, 1, BIT(0)); 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*/ 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(HAD_SET_DISABLE_AUDIO_INT, &caps); had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); had_read_modify(AUD_CONFIG, 0, BIT(0)); /* Reset buffer pointers */ had_write_register(AUD_HDMI_STATUS, 1); had_write_register(AUD_HDMI_STATUS, 0); stream->stream_status = STREAM_DROPPED; break; default: retval = -EINVAL; } return retval; }