From: Lei Zhang Date: Mon, 21 May 2012 12:27:34 +0000 (+0800) Subject: Gfx-Display: refine HDMI audio interface in display driver X-Git-Tag: 2.1b_release~659 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5e2b6fe98834853b5952ae685d6a4d496c37f0ec;p=kernel%2Fkernel-mfld-blackbay.git Gfx-Display: refine HDMI audio interface in display driver BZ: 37468 This is the kernel patch to refine HDMI audio interface in display driver. (1) using ioctl interface to do hotplug event notification instead of doing it in dpms, which gurantees the event won't miss to audio driver. (2) define new query interface to check HDMI audio status instead of using suspend to do audio busy check. (3) modify some of the variable names. Change-Id: I8f24f4a891ae92ca04769facf470f6dba28d0cbd Signed-off-by: Lei Zhang Signed-off-by: Vaibhav Agarwal Signed-off-by: Lei Zhang Reviewed-on: http://android.intel.com:8080/51375 Reviewed-by: Xu, Randy Tested-by: Tong, BoX Reviewed-by: Ai, Ke Reviewed-by: buildbot Tested-by: buildbot --- diff --git a/drivers/staging/mrst/drv/mdfld_hdmi_audio_if.h b/drivers/staging/mrst/drv/mdfld_hdmi_audio_if.h index 719c57c..061542f 100644 --- a/drivers/staging/mrst/drv/mdfld_hdmi_audio_if.h +++ b/drivers/staging/mrst/drv/mdfld_hdmi_audio_if.h @@ -34,8 +34,8 @@ enum had_caps_list { HAD_GET_AUDIO_STATUS, HAD_SET_ENABLE_AUDIO, HAD_SET_DISABLE_AUDIO, - HAD_SET_ENABLE_AUDIO_INT, - HAD_SET_DISABLE_AUDIO_INT, + HAD_SET_ENABLE_AUDIO_INT, + HAD_SET_DISABLE_AUDIO_INT, OTHERS_TBD, }; @@ -46,6 +46,8 @@ enum had_event_type { HAD_EVENT_PM_CHANGING, HAD_EVENT_AUDIO_BUFFER_DONE, HAD_EVENT_AUDIO_BUFFER_UNDERRUN, + HAD_EVENT_QUERY_IS_AUDIO_BUSY, + HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED, }; /** @@ -65,14 +67,15 @@ struct hdmi_audio_query_set_ops{ int (*hdmi_audio_set_caps)(enum had_caps_list set_element , void *capabilties); }; -typedef struct pm_event { - int event; -} pm_event_t; -struct snd_intel_had_interface { - const char *name; - int (*suspend) (void *had_data, pm_event_t event); - int (*resume) (void *had_data); +typedef struct hdmi_audio_event { + int type; +} hdmi_audio_event_t; +struct snd_intel_had_interface { + const char *name; + int (*query) (void *had_data, hdmi_audio_event_t event); + int (*suspend) (void *had_data, hdmi_audio_event_t event); + int (*resume) (void *had_data); }; extern int intel_hdmi_audio_query_capabilities (had_event_call_back audio_callbacks, struct hdmi_audio_registers_ops *reg_ops,struct hdmi_audio_query_set_ops *query_ops); diff --git a/drivers/staging/mrst/drv/psb_drm.h b/drivers/staging/mrst/drv/psb_drm.h index ce94192..621a447 100644 --- a/drivers/staging/mrst/drv/psb_drm.h +++ b/drivers/staging/mrst/drv/psb_drm.h @@ -801,6 +801,7 @@ struct drm_psb_get_pipe_from_crtc_id_arg { #define DRM_PSB_DISP_PLANEB_DISABLE 4 #define DRM_PSB_DISP_PLANEB_ENABLE 5 #define DRM_PSB_HDMI_OSPM_ISLAND_DOWN 6 +#define DRM_PSB_HDMI_NOTIFY_HOTPLUG_TO_AUDIO 7 /*csc gamma setting*/ typedef enum { diff --git a/drivers/staging/mrst/drv/psb_drv.c b/drivers/staging/mrst/drv/psb_drv.c index e0e4673..55dd5a1 100644 --- a/drivers/staging/mrst/drv/psb_drv.c +++ b/drivers/staging/mrst/drv/psb_drv.c @@ -2432,7 +2432,26 @@ static int psb_disp_ioctl(struct drm_device *dev, void *data, DISP_PLANEB_STATUS = ~DISPLAY_PLANE_ENABLE; release_ospm_lock(); } + } else if (dp_ctrl->cmd == DRM_PSB_HDMI_NOTIFY_HOTPLUG_TO_AUDIO) { + if (dp_ctrl->u.data == 0) { + /* notify audio with HDMI unplug event */ + if (dev_priv->mdfld_had_event_callbacks + && !dev_priv->bDVIport) { + DRM_INFO("HDMI plug out to audio driver\n"); + (*dev_priv->mdfld_had_event_callbacks) + (HAD_EVENT_HOT_UNPLUG, dev_priv->had_pvt_data); + } + } else { + /* notify audio with HDMI plug event */ + if (dev_priv->mdfld_had_event_callbacks + && !dev_priv->bDVIport) { + DRM_INFO("HDMI plug in to audio driver\n"); + (*dev_priv->mdfld_had_event_callbacks) + (HAD_EVENT_HOT_PLUG, dev_priv->had_pvt_data); + } + } } + exit: return ret; } diff --git a/drivers/staging/mrst/drv/psb_intel_hdmi.c b/drivers/staging/mrst/drv/psb_intel_hdmi.c index f838e91..ba083cb 100644 --- a/drivers/staging/mrst/drv/psb_intel_hdmi.c +++ b/drivers/staging/mrst/drv/psb_intel_hdmi.c @@ -2026,7 +2026,7 @@ static void mdfld_hdmi_connector_dpms(struct drm_connector *connector, int mode) struct drm_device * dev = connector->dev; struct drm_psb_private * dev_priv = dev->dev_private; int hdmi_audio_busy = 0; - pm_event_t hdmi_audio_event; + hdmi_audio_event_t hdmi_audio_event; u32 dspcntr_val; #ifdef CONFIG_PM_RUNTIME bool panel_on, panel_on2; @@ -2038,7 +2038,7 @@ static void mdfld_hdmi_connector_dpms(struct drm_connector *connector, int mode) /*first, execute dpms*/ /* using suspend to judge whether hdmi audio is playing */ - hdmi_audio_event.event = 0; + hdmi_audio_event.type = 0; if (dev_priv->had_interface && dev_priv->had_pvt_data) hdmi_audio_busy = dev_priv->had_interface->suspend(dev_priv->had_pvt_data, diff --git a/drivers/staging/mrst/drv/psb_powermgmt.c b/drivers/staging/mrst/drv/psb_powermgmt.c index b816f8e..0a89e19 100644 --- a/drivers/staging/mrst/drv/psb_powermgmt.c +++ b/drivers/staging/mrst/drv/psb_powermgmt.c @@ -1772,12 +1772,12 @@ static void dsi_lvds_panel_get_hdmi_audio_status(void) defined(CONFIG_SND_INTELMID_HDMI_AUDIO_MODULE)) struct drm_psb_private *dev_priv = gpDrmDevice->dev_private; struct snd_intel_had_interface *had_interface = dev_priv->had_interface; - pm_event_t hdmi_audio_event; + hdmi_audio_event_t hdmi_audio_event; if (dev_priv->had_pvt_data && hdmi_state) { - hdmi_audio_event.event = 0; + hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; dev_priv->hdmi_audio_busy = - had_interface->suspend(dev_priv->had_pvt_data, + had_interface->query(dev_priv->had_pvt_data, hdmi_audio_event); } #endif @@ -2045,8 +2045,8 @@ int ospm_power_suspend(struct pci_dev *pdev, pm_message_t state) #if (defined(CONFIG_SND_INTELMID_HDMI_AUDIO) || \ defined(CONFIG_SND_INTELMID_HDMI_AUDIO_MODULE)) struct snd_intel_had_interface *had_interface = dev_priv->had_interface; - int hdmi_audio_busy = 0; - pm_event_t hdmi_audio_event; + bool hdmi_audio_suspend = false; + hdmi_audio_event_t hdmi_audio_event; #endif if(gbSuspendInProgress || gbResumeInProgress) { @@ -2067,10 +2067,10 @@ int ospm_power_suspend(struct pci_dev *pdev, pm_message_t state) #if (defined(CONFIG_SND_INTELMID_HDMI_AUDIO) || \ defined(CONFIG_SND_INTELMID_HDMI_AUDIO_MODULE)) if (dev_priv->had_pvt_data && hdmi_state) { - hdmi_audio_event.event = 0; - hdmi_audio_busy = - had_interface->suspend(dev_priv->had_pvt_data, + hdmi_audio_event.type = 0; + ret = had_interface->suspend(dev_priv->had_pvt_data, hdmi_audio_event); + hdmi_audio_suspend = (ret == 0) ? true : false; } #endif @@ -2080,7 +2080,7 @@ int ospm_power_suspend(struct pci_dev *pdev, pm_message_t state) || display_access_count #if (defined(CONFIG_SND_INTELMID_HDMI_AUDIO) || \ defined(CONFIG_SND_INTELMID_HDMI_AUDIO_MODULE)) - || hdmi_audio_busy + || !hdmi_audio_suspend #endif ) ret = -EBUSY; @@ -2664,12 +2664,12 @@ int psb_runtime_idle(struct device *dev) defined(CONFIG_SND_INTELMID_HDMI_AUDIO_MODULE)) struct snd_intel_had_interface *had_interface = dev_priv->had_interface; int hdmi_audio_busy = 0; - pm_event_t hdmi_audio_event; + hdmi_audio_event_t hdmi_audio_event; if (dev_priv->had_pvt_data && hdmi_state) { - hdmi_audio_event.event = 0; + hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; hdmi_audio_busy = - had_interface->suspend(dev_priv->had_pvt_data, + had_interface->query(dev_priv->had_pvt_data, hdmi_audio_event); } #endif diff --git a/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio.c b/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio.c index 766c5fe..8e462cd 100644 --- a/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio.c +++ b/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio.c @@ -1252,6 +1252,7 @@ static struct snd_kcontrol_new had_control_iec958 = { static struct snd_intel_had_interface had_interface = { .name = "hdmi-audio", + .query = hdmi_audio_query, .suspend = hdmi_audio_suspend, .resume = hdmi_audio_resume, }; diff --git a/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio.h b/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio.h index 43df020..ca4de7c 100644 --- a/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio.h +++ b/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio.h @@ -481,7 +481,8 @@ struct snd_intelhad { int had_event_handler(enum had_event_type event_type, void *data); -int hdmi_audio_suspend(void *drv_data, pm_event_t event); +int hdmi_audio_query(void *drv_data, hdmi_audio_event_t event); +int hdmi_audio_suspend(void *drv_data, hdmi_audio_event_t event); 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/drivers/intel_mid_hdmi/intel_mid_hdmi_audio_if.c b/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio_if.c index c8313bd..f20998f 100644 --- a/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio_if.c +++ b/sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio_if.c @@ -37,6 +37,60 @@ static int flag_en_allbufs; /** + * 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, hdmi_audio_event_t event) +{ + struct snd_pcm_substream *substream; + struct had_pvt_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; + switch (event.type) { + case HAD_EVENT_QUERY_IS_AUDIO_BUSY: + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + + if ((had_stream->stream_status > HAD_RUNNING_SILENCE) || + 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 * *@haddata: pointer to HAD private data @@ -45,7 +99,7 @@ static int flag_en_allbufs; * This function is called by client driver to suspend the * hdmi audio. */ -int hdmi_audio_suspend(void *haddata, pm_event_t event) +int hdmi_audio_suspend(void *haddata, hdmi_audio_event_t event) { int caps, retval = 0; struct had_pvt_data *had_stream;