• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include "hdf_log.h"
10 #include "hdmi_core.h"
11 #include "osal_mem.h"
12 
13 #define HDF_LOG_TAG hdmi_event_c
14 
HdmiEventPostMsg(struct HdmiCntlr * cntlr,struct HdmiEventMsg * event)15 static int32_t HdmiEventPostMsg(struct HdmiCntlr *cntlr, struct HdmiEventMsg *event)
16 {
17     int32_t ret;
18 
19     if (cntlr == NULL) {
20         return HDF_ERR_INVALID_OBJECT;
21     }
22     if (event == NULL) {
23         return HDF_ERR_INVALID_PARAM;
24     }
25 
26     if (event->block) {
27         (void)OsalSemInit(&event->sem, 0);
28     }
29     (void)PlatformQueueAddMsg(cntlr->msgQueue, &event->msg);
30     if (!event->block) {
31         return HDF_SUCCESS;
32     }
33 
34     ret = OsalSemWait(&event->sem, HDF_WAIT_FOREVER);
35     (void)OsalSemDestroy(&event->sem);
36     OsalMemFree(event);
37     if (ret != HDF_SUCCESS) {
38         HDF_LOGE("HdmiEventPostMsg: wait hdmi event msg fail!");
39     }
40     return ret;
41 }
42 
HdmiHpdStatusGet(struct HdmiCntlr * cntlr)43 static bool HdmiHpdStatusGet(struct HdmiCntlr *cntlr)
44 {
45     bool ret = false;
46 
47     if (cntlr == NULL || cntlr->ops == NULL || cntlr->ops->hotPlugStateGet == NULL) {
48         return ret;
49     }
50 
51     HdmiCntlrLock(cntlr);
52     ret = cntlr->ops->hotPlugStateGet(cntlr);
53     HdmiCntlrUnlock(cntlr);
54     return ret;
55 }
56 
HdmiHpdStatusDelayGet(struct HdmiCntlr * cntlr)57 bool HdmiHpdStatusDelayGet(struct HdmiCntlr *cntlr)
58 {
59     uint32_t i;
60 
61     /*
62      * An HDMI Sink shall indicate any change to the contents of the EDID by driving a low voltage level pulse
63      * on the Hot Plug Detect pin. This pluse shall be at least 100 msec.
64      */
65     for (i = 0; i < HDMI_READ_HPD_STATUS_DELAY; i++) {
66         if (HdmiHpdStatusGet(cntlr) == true) {
67             return true;
68         }
69         OsalMSleep(1);
70     }
71     return false;
72 }
73 
HdmiAddEventMsgToQueue(struct HdmiCntlr * cntlr,int32_t code,bool block,void * data)74 static int32_t HdmiAddEventMsgToQueue(struct HdmiCntlr *cntlr, int32_t code, bool block, void *data)
75 {
76     struct HdmiEventMsg *event = NULL;
77 
78     if (cntlr == NULL) {
79         return HDF_ERR_INVALID_OBJECT;
80     }
81 
82     event = (struct HdmiEventMsg *)OsalMemCalloc(sizeof(struct HdmiEventMsg));
83     if (event == NULL) {
84         HDF_LOGE("HdmiAddEventMsgToQueue: OsalMemCalloc fail!n");
85         return HDF_ERR_MALLOC_FAIL;
86     }
87     event->msg.code = code;
88     event->msg.data = (void *)cntlr;
89     event->block = block;
90     event->priv = data;
91     return HdmiEventPostMsg(cntlr, event);
92 }
93 
HdmiEventHotPlugHandleComm(struct HdmiCntlr * cntlr)94 static int32_t HdmiEventHotPlugHandleComm(struct HdmiCntlr *cntlr)
95 {
96     int32_t ret;
97 
98     cntlr->event.plugged = true;
99     HDF_LOGD("Hdmi sink device plugged!");
100     if (cntlr->hdmi == NULL) {
101         ret = HdmiCntlrAllocDev(cntlr);
102         if (ret != HDF_SUCCESS) {
103             cntlr->event.plugged = false;
104             cntlr->event.hpdDetected = false;
105             return ret;
106         }
107         HDF_LOGE("HdmiEventHotPlugHandleComm HdmiCntlrAllocDev success.");
108     }
109 
110     /* Update EDID. */
111     if (HdmiEdidReset(&(cntlr->hdmi->edid)) != HDF_SUCCESS) {
112         HDF_LOGE("edid reset fail.");
113         ret = HDF_ERR_IO;
114         cntlr->event.plugged = false;
115         cntlr->event.hpdDetected = false;
116         return ret;
117     }
118     ret = HdmiEdidRawDataRead(&(cntlr->hdmi->edid), &(cntlr->ddc));
119     if (ret != HDF_SUCCESS) {
120         cntlr->event.plugged = false;
121         cntlr->event.hpdDetected = false;
122         return ret;
123     }
124     ret = HdmiEdidPhase(&(cntlr->hdmi->edid));
125     if (ret != HDF_SUCCESS) {
126         cntlr->event.plugged = false;
127         cntlr->event.hpdDetected = false;
128         return ret;
129     }
130 
131     cntlr->event.hpdDetected = true;
132     if (cntlr->event.callback.callbackFunc != NULL) {
133         cntlr->event.callback.callbackFunc(cntlr->event.callback.data, true);
134     }
135     return HDF_SUCCESS;
136 }
137 
HdmiEventHotPlugHandle(struct HdmiCntlr * cntlr)138 static int32_t HdmiEventHotPlugHandle(struct HdmiCntlr *cntlr)
139 {
140     if (HdmiHpdStatusDelayGet(cntlr) == false) {
141         HDF_LOGD("not detect HPD.");
142         return HDF_ERR_IO;
143     }
144 
145     if (cntlr->event.plugged == true) {
146         HDF_LOGD("HdmiEventHotPlugHandle: hdp state not change");
147         return HDF_SUCCESS;
148     }
149     return HdmiEventHotPlugHandleComm(cntlr);
150 }
151 
HdmiEventHotUnplugHandle(struct HdmiCntlr * cntlr)152 static int32_t HdmiEventHotUnplugHandle(struct HdmiCntlr *cntlr)
153 {
154     if (cntlr->event.plugged == false) {
155         HDF_LOGD("HdmiEventHotUnplugHandle: plug state not change");
156         return HDF_SUCCESS;
157     }
158 
159     HdmiCntlrClose(cntlr);
160     HdmiCntlrFreeDev(cntlr);
161     cntlr->event.plugged = false;
162     cntlr->event.hpdDetected = false;
163     if (cntlr->event.callback.callbackFunc != NULL) {
164         cntlr->event.callback.callbackFunc(cntlr->event.callback.data, false);
165     }
166     return HDF_SUCCESS;
167 }
168 
HdmiEventDetectSinkHandle(struct HdmiCntlr * cntlr)169 static int32_t HdmiEventDetectSinkHandle(struct HdmiCntlr *cntlr)
170 {
171     if (HdmiHpdStatusDelayGet(cntlr) == false) {
172         HDF_LOGD("not detect HPD.");
173         return HDF_SUCCESS;
174     }
175     return HdmiEventHotPlugHandleComm(cntlr);
176 }
177 
HdmiEventCecMsgHandle(struct HdmiCntlr * cntlr,struct HdmiCecMsg * msg)178 static int32_t HdmiEventCecMsgHandle(struct HdmiCntlr *cntlr, struct HdmiCecMsg *msg)
179 {
180     if (msg == NULL) {
181         return HDF_ERR_INVALID_OBJECT;
182     }
183 
184     return HdmiCecReceivedMsg(cntlr->cec, msg);
185 }
186 
HdmiEventHdrZeroDrmIfTimeout(struct HdmiCntlr * cntlr)187 static int32_t HdmiEventHdrZeroDrmIfTimeout(struct HdmiCntlr *cntlr)
188 {
189     return HdmiHdrDrmInfoFrameStop(cntlr->hdr);
190 }
191 
HdmiEventSwitchToHdrModeTimeout(struct HdmiCntlr * cntlr)192 static int32_t HdmiEventSwitchToHdrModeTimeout(struct HdmiCntlr *cntlr)
193 {
194     return HdmiHdrModeChangeTimeout(cntlr->hdr);
195 }
196 
HdmiEventMsgHandleDefault(struct PlatformQueue * queue,struct PlatformMsg * msg)197 int32_t HdmiEventMsgHandleDefault(struct PlatformQueue *queue, struct PlatformMsg *msg)
198 {
199     int32_t ret;
200     struct HdmiCntlr *cntlr = NULL;
201     struct HdmiEventMsg *event = NULL;
202 
203     if (queue == NULL || msg == NULL) {
204         HDF_LOGE("HdmiEventMsgHandleDefault: msg or queue is null!");
205         return HDF_ERR_INVALID_OBJECT;
206     }
207 
208     cntlr = (struct HdmiCntlr *)queue->data;
209     if (cntlr == NULL) {
210         HDF_LOGE("HdmiEventMsgHandleDefault: cntlr is null!");
211         return HDF_ERR_INVALID_OBJECT;
212     }
213     event = (struct HdmiEventMsg *)msg;
214     switch (msg->code) {
215         case HDMI_EVENT_HOTPLUG:
216             ret = HdmiEventHotPlugHandle(cntlr);
217             break;
218         case HDMI_EVENT_HOTUNPLUG:
219             ret = HdmiEventHotUnplugHandle(cntlr);
220             break;
221         case HDMI_EVENT_DETECT_SINK:
222             ret = HdmiEventDetectSinkHandle(cntlr);
223             break;
224         case HDMI_EVENT_CEC_MSG:
225             ret = HdmiEventCecMsgHandle(cntlr, event->priv);
226             break;
227         case HDMI_EVENT_ZERO_DRMIF_TIMEOUT:
228             ret = HdmiEventHdrZeroDrmIfTimeout(cntlr);
229             break;
230         case HDMI_EVENT_SWITCH_TO_HDRMODE_TIMEOUT:
231             ret = HdmiEventSwitchToHdrModeTimeout(cntlr);
232             break;
233         default:
234             ret = HDF_ERR_NOT_SUPPORT;
235             break;
236     }
237 
238     if (!event->block) {
239         OsalMemFree(event);
240     } else {
241         (void)OsalSemPost(&event->sem);
242     }
243 
244     return ret;
245 }
246 
HdmiEventHandle(struct HdmiCntlr * cntlr,enum HdmiEventType event,void * data)247 int32_t HdmiEventHandle(struct HdmiCntlr *cntlr, enum HdmiEventType event, void *data)
248 {
249     int32_t ret = HDF_SUCCESS;
250 
251     if (cntlr == NULL) {
252         HDF_LOGE("HdmiEventHandleIrq: cntlr is null!");
253         return HDF_ERR_INVALID_OBJECT;
254     }
255     switch (event) {
256         case HDMI_EVENT_HOTPLUG:
257             ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_HOTPLUG, false, data);
258             break;
259         case HDMI_EVENT_HOTUNPLUG:
260             ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_HOTUNPLUG, false, data);
261             break;
262         case HDMI_EVENT_DETECT_SINK:
263             ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_DETECT_SINK, false, data);
264             break;
265         case HDMI_EVENT_CEC_MSG:
266             ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_CEC_MSG, false, data);
267             break;
268         case HDMI_EVENT_HDCP_MSG:
269             ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_HDCP_MSG, false, data);
270             break;
271         case HDMI_EVENT_ZERO_DRMIF_TIMEOUT:
272             ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_ZERO_DRMIF_TIMEOUT, false, data);
273             break;
274         case HDMI_EVENT_SWITCH_TO_HDRMODE_TIMEOUT:
275             ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_SWITCH_TO_HDRMODE_TIMEOUT, false, data);
276             break;
277         default:
278             HDF_LOGE("event %d is not support", event);
279             break;
280     }
281     return ret;
282 }
283