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