天天看點

Android HDMI插拔 audio狀态上報流程,基于高通平台

struct msm_ext_disp {
	struct platform_device *pdev;
	enum msm_ext_disp_type current_disp;
	struct msm_ext_disp_audio_codec_ops *ops;
	struct switch_dev hdmi_sdev;
	struct switch_dev audio_sdev;
	bool ack_enabled;
	bool audio_session_on;
	struct list_head display_list;
	struct mutex lock;
	struct completion hpd_comp;
	bool update_audio;
	u32 flags;
};

Freamwork:
WiredAccessoryManager:
	WiredAccessoryManager  //監聽Uevent;

msm_ext_disp_register_intf
init_data->intf_ops.hpd = msm_ext_disp_hpd;

msm_ext_disp_hpd
	msm_ext_disp_process_audio
		msm_ext_disp_send_audio_notification
			switch_set_state
			
sdm660_64:/sys/class/switch/hdmi_audio/subsystem/hdmi_audio/state 			

./msm-4.4/drivers/video/fbdev/msm/mdss_hdmi_tx.c:419:	if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.hpd) 

hdmi_tx_send_audio_notification






kernel notify 過程;
struct lt9611 {
......
        struct notifier_block lt9611_notif;
}


lt9611_notify_clients(&pdata->dev_info, MSM_DBA_CB_AUDIO_CONNECT);

pdata->lt9611_notif.notifier_call = lt9611_notifier_callback;
                                       
static int lt9611_notifier_callback(struct notifier_block *self, unsigned long event, void *data)
{
	struct fb_event *evdata = data;
	int *blank;
	struct lt9611 *pdata = container_of(self, struct lt9611, lt9611_notif);
	if (evdata && evdata->data && event == FB_EVENT_BLANK) {
		blank = evdata->data;
		if (*blank == FB_BLANK_UNBLANK){
			if(lt9611_connected == 0){
				lt9611_notify_clients(&pdata->dev_info,MSM_DBA_CB_HPD_CONNECT);
				lt9611_connected = 1;
				pr_err("%s: Rx CONNECTED\n", __func__);
			}
		}//lt9611_resume(pdata);
......
}

fb_register_client(&pdata->lt9611_notif);

./drivers/video/fbdev/core/fb_notify.c
int fb_register_client(struct notifier_block *nb)                                                                                     
{
    return blocking_notifier_chain_register(&fb_notifier_list, nb);
}


int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
        struct notifier_block *n) 
{                                                                                                                                         
......
        return notifier_chain_register(&nh->head, n); 
......
}

static int notifier_chain_register(struct notifier_block **nl,                                                                            
        struct notifier_block *n) 
{
    while ((*nl) != NULL) {
        if (n->priority > (*nl)->priority)
            break;
        nl = &((*nl)->next);
    }   
    n->next = *nl;
    rcu_assign_pointer(*nl, n); 
    return 0;
}


static void lt9611_notify_clients(struct msm_dba_device_info *dev,
                enum msm_dba_callback_event event)
{
        struct msm_dba_client_info *c;
        struct list_head *pos = NULL;

        if (!dev) {
                pr_err("%s: invalid input\n", __func__);
                return;
        }
        list_for_each(pos, &dev->client_list) {
                c = list_entry(pos, struct msm_dba_client_info, list);

                pr_err("%s: notifying event %d to client %s\n", __func__,
                        event, c->client_name);=
                if (c && c->cb)
                        c->cb(c->cb_data, event);
        }
}


./kernel/include/video/msm_dba.h

 enum msm_dba_callback_event {                                                                                                            
    MSM_DBA_CB_REMOTE_INT = BIT(0),
    MSM_DBA_CB_HDCP_LINK_AUTHENTICATED = BIT(1),
    MSM_DBA_CB_HDCP_LINK_UNAUTHENTICATED = BIT(2),
    MSM_DBA_CB_HPD_CONNECT = BIT(3),
    MSM_DBA_CB_HPD_DISCONNECT = BIT(4),
    MSM_DBA_CB_VIDEO_FAILURE = BIT(5),
    MSM_DBA_CB_AUDIO_FAILURE = BIT(6),
    MSM_DBA_CB_CEC_WRITE_SUCCESS = BIT(7),
    MSM_DBA_CB_CEC_WRITE_FAIL = BIT(8),
    MSM_DBA_CB_CEC_READ_PENDING = BIT(9),
    MSM_DBA_CB_PRE_RESET = BIT(10),
    MSM_DBA_CB_POST_RESET = BIT(11),
    MSM_DBA_CB_DDC_I2C_ERROR = BIT(12),
    MSM_DBA_CB_DDC_TIMEOUT = BIT(13),
};
           

繼續閱讀