1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "drv_hdmi_event.h"
20
21 #define HDMI_EVENT_NOT_MACH_SLEEP 500
22 #define HDMI_EVENT_READ_SLEEP 100
23 #define HDMI_EVENT_DEINIT_SLEEP 200
24
25 static hdmi_event_info g_event_info[HDMI_DEVICE_ID_BUTT];
26
event_info_ptr_get(hdmi_device_id hdmi)27 static hdmi_event_info *event_info_ptr_get(hdmi_device_id hdmi)
28 {
29 if (hdmi < HDMI_DEVICE_ID_BUTT) {
30 return &g_event_info[hdmi];
31 }
32 return HI_NULL;
33 }
34
event_type_counter(hdmi_event_pool * pool,hdmi_event event,hi_bool write)35 static hi_s32 event_type_counter(hdmi_event_pool *pool, hdmi_event event, hi_bool write)
36 {
37 switch (event) {
38 case HDMI_EVENT_HOTPLUG:
39 write ? pool->run_cnt.hpd_wr_cnt++ : pool->run_cnt.hpd_rd_cnt++;
40 break;
41 case HDMI_EVENT_HOTUNPLUG:
42 write ? pool->run_cnt.unhpd_wr_cnt++ : pool->run_cnt.unhpd_rd_cnt++;
43 break;
44 case HDMI_EVENT_EDID_FAIL:
45 write ? pool->run_cnt.edid_fail_wr_cnt++ : pool->run_cnt.edid_fail_rd_cnt++;
46 break;
47 case HDMI_EVENT_RSEN_CONNECT:
48 write ? pool->run_cnt.rsen_con_wr_cnt++ : pool->run_cnt.rsen_con_rd_cnt++;
49 break;
50 case HDMI_EVENT_RSEN_DISCONNECT:
51 write ? pool->run_cnt.rsen_dis_wr_cnt++ : pool->run_cnt.rsen_dis_rd_cnt++;
52 break;
53 default:
54 break;
55 }
56
57 return HI_SUCCESS;
58 }
59
event_mach_id(hdmi_event_info * evt_info,hi_u32 pool_id)60 static hi_u32 event_mach_id(hdmi_event_info *evt_info, hi_u32 pool_id)
61 {
62 hi_u32 i;
63 hdmi_event_pool *tmp_pool = HI_NULL;
64
65 hdmi_mutex_lock(evt_info->event_mutex);
66 if (evt_info->total == 0) {
67 hdmi_warn("event pool list is empty\n");
68 hdmi_mutex_unlock(evt_info->event_mutex);
69 return HI_SUCCESS;
70 }
71
72 /* find a match proc */
73 for (i = 0, tmp_pool = &evt_info->pool[0]; i < HDMI_EVENT_POOL_CNT; i++, tmp_pool++) {
74 if (tmp_pool->ctrl.pool_id == pool_id) {
75 break;
76 }
77 }
78 hdmi_mutex_unlock(evt_info->event_mutex);
79
80 return i;
81 }
82
drv_hdmi_event_init(hdmi_device_id hdmi_id)83 hi_s32 drv_hdmi_event_init(hdmi_device_id hdmi_id)
84 {
85 hdmi_event_info *evt_info = HI_NULL;
86
87 hdmi_check_max_return(hdmi_id, HDMI_DEVICE_ID_BUTT - 1, HI_FAILURE);
88 evt_info = event_info_ptr_get(hdmi_id);
89 hdmi_if_null_warn_return(evt_info, HI_FAILURE);
90
91 if (evt_info->init != HI_TRUE) {
92 (hi_void)memset_s(evt_info, sizeof(hdmi_event_info), 0, sizeof(hdmi_event_info));
93 /* init */
94 osal_wait_init(&evt_info->wr_queue);
95 osal_sema_init(&evt_info->event_mutex, 1);
96 evt_info->total = 0;
97 evt_info->init = HI_TRUE;
98 evt_info->wakeup_all = HI_FALSE;
99 }
100
101 return HI_SUCCESS;
102 }
103
drv_hdmi_event_deinit(hdmi_device_id hdmi_id)104 hi_s32 drv_hdmi_event_deinit(hdmi_device_id hdmi_id)
105 {
106 hdmi_event_info *evt_info = HI_NULL;
107
108 hdmi_check_max_return(hdmi_id, HDMI_DEVICE_ID_BUTT - 1, HI_FAILURE);
109 evt_info = event_info_ptr_get(hdmi_id);
110 hdmi_if_null_warn_return(evt_info, HI_FAILURE);
111 hdmi_if_false_warn_return(evt_info->init, HI_FAILURE);
112
113 /* wake up all process which is waiting for event */
114 hdmi_mutex_lock(evt_info->event_mutex);
115 evt_info->wakeup_all = HI_TRUE;
116 hdmi_mutex_unlock(evt_info->event_mutex);
117
118 osal_wakeup(&evt_info->wr_queue);
119 osal_msleep(HDMI_EVENT_DEINIT_SLEEP);
120
121 hdmi_mutex_lock(evt_info->event_mutex);
122 (hi_void)memset_s(evt_info->pool, sizeof(evt_info->pool), 0, sizeof(evt_info->pool));
123 evt_info->total = 0;
124 evt_info->init = HI_FALSE;
125 hdmi_mutex_unlock(evt_info->event_mutex);
126 osal_sema_destroy(&evt_info->event_mutex);
127 osal_wait_destroy(&evt_info->wr_queue);
128
129 return HI_SUCCESS;
130 }
131
drv_hdmi_event_pool_malloc(hdmi_device_id hdmi_id,hi_u32 * pool_id)132 hi_s32 drv_hdmi_event_pool_malloc(hdmi_device_id hdmi_id, hi_u32 *pool_id)
133 {
134 hi_u32 i;
135 hi_u32 cur_gid;
136 hdmi_event_pool *tmp_pool = HI_NULL;
137 hdmi_event_info *evt_info = HI_NULL;
138
139 hdmi_check_max_return(hdmi_id, HDMI_DEVICE_ID_BUTT - 1, HI_FAILURE);
140 evt_info = event_info_ptr_get(hdmi_id);
141 hdmi_if_null_warn_return(evt_info, HI_FAILURE);
142 hdmi_if_false_warn_return(evt_info->init, HI_FAILURE);
143
144 cur_gid = (hi_u32)hdmi_get_current_id();
145 /* malloc a new pool element & init */
146 hdmi_mutex_lock(evt_info->event_mutex);
147
148 /* check ID exist */
149 for (i = 0, tmp_pool = &evt_info->pool[0]; i < HDMI_EVENT_POOL_CNT; i++, tmp_pool++) {
150 if (tmp_pool->ctrl.pool_id == cur_gid) {
151 hdmi_warn("proc ID=%u exist!\n", cur_gid);
152 hdmi_mutex_unlock(evt_info->event_mutex);
153 return HDMI_EVENT_ID_EXIST;
154 }
155 }
156
157 for (i = 0, tmp_pool = &evt_info->pool[0]; i < HDMI_EVENT_POOL_CNT; i++, tmp_pool++) {
158 if (!tmp_pool->ctrl.pool_id) {
159 break;
160 }
161 }
162
163 if (i >= HDMI_EVENT_POOL_CNT) {
164 hdmi_warn("proc ID=%u no event sercer,pool max cnt = %u!\n", cur_gid, i);
165 hdmi_mutex_unlock(evt_info->event_mutex);
166 return HI_FAILURE;
167 }
168
169 (hi_void)memset_s(&tmp_pool->ctrl, sizeof(tmp_pool->ctrl), 0, sizeof(hdmi_event_run_ctrl));
170 (hi_void)memset_s(&tmp_pool->run_cnt, sizeof(tmp_pool->run_cnt), 0, sizeof(hdmi_event_run_cnt));
171 tmp_pool->ctrl.pool_id = cur_gid;
172 if (pool_id != HI_NULL) {
173 *pool_id = tmp_pool->ctrl.pool_id;
174 }
175 tmp_pool->ctrl.wakeup_flag = HI_FALSE;
176 for (i = 0; i < HDMI_EVENT_POOL_SIZE; i++) {
177 tmp_pool->ctrl.event_pool[i] = HDMI_EVENT_BUTT;
178 }
179 evt_info->total++;
180 hdmi_mutex_unlock(evt_info->event_mutex);
181
182 return HI_SUCCESS;
183 }
184
drv_hdmi_event_pool_free(hdmi_device_id hdmi_id,hi_u32 pool_id)185 hi_s32 drv_hdmi_event_pool_free(hdmi_device_id hdmi_id, hi_u32 pool_id)
186 {
187 hi_u32 i;
188 hdmi_event_pool *tmp_pool = HI_NULL;
189 hdmi_event_info *evt_info = HI_NULL;
190
191 hdmi_check_max_return(hdmi_id, HDMI_DEVICE_ID_BUTT - 1, HI_FAILURE);
192 evt_info = event_info_ptr_get(hdmi_id);
193 hdmi_if_null_warn_return(evt_info, HI_FAILURE);
194 hdmi_if_false_warn_return(evt_info->init, HI_FAILURE);
195
196 hdmi_mutex_lock(evt_info->event_mutex);
197 /* find a match ID and free it */
198 for (i = 0, tmp_pool = &evt_info->pool[0]; i < HDMI_EVENT_POOL_CNT; i++, tmp_pool++) {
199 if (tmp_pool->ctrl.pool_id == pool_id) {
200 evt_info->total--;
201 tmp_pool->ctrl.wakeup_flag = HI_TRUE;
202 osal_wakeup(&evt_info->wr_queue);
203 tmp_pool->ctrl.pool_id = 0;
204 hdmi_info("delete proc(%u) node\n", pool_id);
205 break;
206 }
207 }
208 hdmi_mutex_unlock(evt_info->event_mutex);
209
210 /* can't find a match ID */
211 if (i >= HDMI_EVENT_POOL_CNT) {
212 hdmi_err("proc id(%u) free fail\n", pool_id);
213 return HI_FAILURE;
214 }
215
216 return HI_SUCCESS;
217 }
218
drv_hdmi_event_pool_write(hdmi_device_id hdmi_id,hdmi_event event)219 hi_s32 drv_hdmi_event_pool_write(hdmi_device_id hdmi_id, hdmi_event event)
220 {
221 hi_u32 i;
222 hdmi_event_pool *tmp_pool = HI_NULL;
223 hdmi_event_info *evt_info = HI_NULL;
224
225 hdmi_check_max_return(hdmi_id, HDMI_DEVICE_ID_BUTT - 1, HI_FAILURE);
226 evt_info = event_info_ptr_get(hdmi_id);
227 hdmi_if_null_warn_return(evt_info, HI_FAILURE);
228 hdmi_if_false_warn_return(evt_info->init, HI_FAILURE);
229
230 if ((event < HDMI_EVENT_HOTPLUG) || (event > HDMI_EVENT_HDCP_USERSETTING)) {
231 hdmi_warn("the event(0x%x) invalid ,we don't write!\n", event);
232 return HI_FAILURE;
233 }
234
235 hdmi_mutex_lock(evt_info->event_mutex);
236 if (evt_info->total == 0) {
237 hdmi_warn("event pool is empty\n");
238 hdmi_mutex_unlock(evt_info->event_mutex);
239 return HI_SUCCESS;
240 }
241
242 /* write event into all event pool in the list */
243 for (i = 0, tmp_pool = &evt_info->pool[0]; i < HDMI_EVENT_POOL_CNT; i++, tmp_pool++) {
244 if (tmp_pool->ctrl.pool_id) {
245 /* the event pool is overflow */
246 if ((tmp_pool->ctrl.event_pool[tmp_pool->ctrl.write_ptr] >= HDMI_EVENT_HOTPLUG) &&
247 (tmp_pool->ctrl.event_pool[tmp_pool->ctrl.write_ptr] <= HDMI_EVENT_HDCP_USERSETTING)) {
248 tmp_pool->run_cnt.err_wd_cnt++;
249 tmp_pool->ctrl.readable_cnt--;
250 tmp_pool->ctrl.read_ptr = (tmp_pool->ctrl.write_ptr + 1) % HDMI_EVENT_POOL_SIZE;
251 hdmi_warn("the event pool of proc(%u) is overflow\n", tmp_pool->ctrl.pool_id);
252 }
253 tmp_pool->ctrl.event_pool[tmp_pool->ctrl.write_ptr++] = event;
254 tmp_pool->ctrl.write_ptr %= HDMI_EVENT_POOL_SIZE;
255 event_type_counter(tmp_pool, event, HI_TRUE);
256 tmp_pool->ctrl.readable_cnt++;
257 osal_wakeup(&evt_info->wr_queue);
258 hdmi_info("the event(0x%x) is writed into event pool of proc(%u) success\n",
259 event, tmp_pool->ctrl.pool_id);
260 }
261 }
262 hdmi_mutex_unlock(evt_info->event_mutex);
263
264 return HI_SUCCESS;
265 }
266
drv_hdmi_event_callback(const hi_void * param)267 hi_s32 drv_hdmi_event_callback(const hi_void *param)
268 {
269 const hdmi_event_wait_callback *tmp = HI_NULL;
270 hi_s32 result;
271
272 tmp = (const hdmi_event_wait_callback *)param;
273 result =
274 (tmp->evt_info->wakeup_all || tmp->tmp_pool->ctrl.wakeup_flag || (tmp->tmp_pool->ctrl.readable_cnt > 0));
275
276 return result;
277 }
278
drv_hdmi_event_pool_read(hdmi_device_id hdmi_id,hi_u32 pool_id,hdmi_event * event)279 hi_s32 drv_hdmi_event_pool_read(hdmi_device_id hdmi_id, hi_u32 pool_id, hdmi_event *event)
280 {
281 hi_u32 i;
282 hi_s32 ret;
283 hdmi_event_pool *tmp_pool = HI_NULL;
284 hdmi_event_info *evt_info = HI_NULL;
285 hdmi_event_wait_callback callback = {0};
286
287 evt_info = event_info_ptr_get(hdmi_id);
288 hdmi_if_null_warn_return(evt_info, HI_FAILURE);
289 hdmi_if_null_warn_return(event, HI_FAILURE);
290 hdmi_if_false_warn_return(evt_info->init, HI_FAILURE);
291
292 *event = HDMI_EVENT_BUTT;
293 i = event_mach_id(evt_info, pool_id);
294 if (i >= HDMI_EVENT_POOL_CNT) {
295 hdmi_err("the proc(%u) is not find\n", pool_id);
296 osal_msleep(HDMI_EVENT_NOT_MACH_SLEEP);
297 return HI_FAILURE;
298 }
299 tmp_pool = &evt_info->pool[i];
300 callback.evt_info = evt_info;
301 callback.tmp_pool = tmp_pool;
302 ret = osal_wait_event_timeout_interruptible(&(evt_info->wr_queue), drv_hdmi_event_callback,
303 (hi_void *)&callback, HDMI_EVENT_READ_SLEEP);
304 if (ret <= 0) {
305 return HI_SUCCESS;
306 }
307
308 hdmi_mutex_lock(evt_info->event_mutex);
309 if (tmp_pool->ctrl.readable_cnt == 0) {
310 hdmi_mutex_unlock(evt_info->event_mutex);
311 return HI_SUCCESS;
312 } else {
313 *event = tmp_pool->ctrl.event_pool[tmp_pool->ctrl.read_ptr];
314 tmp_pool->ctrl.event_pool[tmp_pool->ctrl.read_ptr] = HDMI_EVENT_BUTT;
315 tmp_pool->ctrl.read_ptr = (tmp_pool->ctrl.read_ptr + 1) % HDMI_EVENT_POOL_SIZE;
316 tmp_pool->ctrl.wakeup_flag = HI_FALSE;
317 if ((*event >= HDMI_EVENT_HOTPLUG) && (*event <= HDMI_EVENT_HDCP_USERSETTING)) {
318 tmp_pool->ctrl.readable_cnt--;
319 event_type_counter(tmp_pool, *event, HI_FALSE);
320 ret = HI_SUCCESS;
321 hdmi_info("the proc(%u) poll event(0x%x) success\n", tmp_pool->ctrl.pool_id, *event);
322 } else {
323 tmp_pool->run_cnt.err_rd_cnt++;
324 ret = HI_FAILURE;
325 }
326 }
327 hdmi_mutex_unlock(evt_info->event_mutex);
328
329 return ret;
330 }
331
drv_hdmi_event_pool_status_get(hdmi_device_id hdmi_id,hi_u32 pool_num,hdmi_event_run_ctrl * ctrl,hdmi_event_run_cnt * cnt)332 hi_s32 drv_hdmi_event_pool_status_get(hdmi_device_id hdmi_id, hi_u32 pool_num,
333 hdmi_event_run_ctrl *ctrl, hdmi_event_run_cnt *cnt)
334 {
335 errno_t ret;
336 hi_u32 i;
337 hi_u32 j = 0;
338 hdmi_event_pool *tmp_pool = HI_NULL;
339 hdmi_event_info *evt_info = HI_NULL;
340
341 hdmi_check_max_return(hdmi_id, HDMI_DEVICE_ID_BUTT - 1, HI_FAILURE);
342 evt_info = event_info_ptr_get(hdmi_id);
343 hdmi_if_null_warn_return(evt_info, HI_FAILURE);
344 hdmi_if_null_warn_return(ctrl, HI_FAILURE);
345 hdmi_if_null_warn_return(cnt, HI_FAILURE);
346 hdmi_if_false_warn_return(evt_info->init, HI_FAILURE);
347
348 (hi_void)memset_s(ctrl, sizeof(hdmi_event_run_ctrl), 0, sizeof(hdmi_event_run_ctrl));
349 (hi_void)memset_s(cnt, sizeof(hdmi_event_run_cnt), 0, sizeof(hdmi_event_run_cnt));
350
351 hdmi_mutex_lock(evt_info->event_mutex);
352 if ((pool_num > evt_info->total) || (pool_num == 0)) {
353 hdmi_warn("the input pool num(%u) is wrong,event pool range is [1~%u]\n", pool_num, evt_info->total);
354 hdmi_mutex_unlock(evt_info->event_mutex);
355 return HI_FAILURE;
356 }
357
358 if (evt_info->total == 0) {
359 hdmi_warn("event pool is empty\n");
360 hdmi_mutex_unlock(evt_info->event_mutex);
361 return HI_SUCCESS;
362 }
363
364 /* find a match ID and copy status */
365 for (i = 0, tmp_pool = &evt_info->pool[0]; i < HDMI_EVENT_POOL_CNT; i++, tmp_pool++) {
366 if (tmp_pool->ctrl.pool_id) {
367 j++;
368 if (j == pool_num) {
369 ret = memcpy_s(ctrl, sizeof(*ctrl), &tmp_pool->ctrl, sizeof(hdmi_event_run_ctrl));
370 hdmi_unlock_unequal_eok_return(ret, evt_info->event_mutex, HI_ERR_HDMI_INVALID_PARA);
371 ret = memcpy_s(cnt, sizeof(*cnt), &tmp_pool->run_cnt, sizeof(hdmi_event_run_cnt));
372 hdmi_unlock_unequal_eok_return(ret, evt_info->event_mutex, HI_ERR_HDMI_INVALID_PARA);
373 break;
374 }
375 }
376 }
377 hdmi_mutex_unlock(evt_info->event_mutex);
378
379 return HI_SUCCESS;
380 }
381
drv_hdmi_event_pool_total_get(hdmi_device_id hdmi_id,hi_u32 * total)382 hi_s32 drv_hdmi_event_pool_total_get(hdmi_device_id hdmi_id, hi_u32 *total)
383 {
384 hdmi_event_info *evt_info = HI_NULL;
385
386 hdmi_check_max_return(hdmi_id, HDMI_DEVICE_ID_BUTT - 1, HI_FAILURE);
387 evt_info = event_info_ptr_get(hdmi_id);
388 hdmi_if_null_warn_return(evt_info, HI_FAILURE);
389 hdmi_if_null_warn_return(total, HI_FAILURE);
390 hdmi_if_false_warn_return(evt_info->init, HI_FAILURE);
391
392 hdmi_mutex_lock(evt_info->event_mutex);
393 *total = evt_info->total;
394 hdmi_mutex_unlock(evt_info->event_mutex);
395
396 return HI_SUCCESS;
397 }
398
drv_hdmi_event_pool_id_get(hdmi_device_id hdmi_id,hi_u32 * thread_id)399 hi_s32 drv_hdmi_event_pool_id_get(hdmi_device_id hdmi_id, hi_u32 *thread_id)
400 {
401 hdmi_event_info *evt_info = HI_NULL;
402
403 hdmi_check_max_return(hdmi_id, HDMI_DEVICE_ID_BUTT - 1, HI_FAILURE);
404 evt_info = event_info_ptr_get(hdmi_id);
405 hdmi_if_null_warn_return(evt_info, HI_FAILURE);
406 hdmi_if_null_warn_return(thread_id, HI_FAILURE);
407 hdmi_if_false_warn_return(evt_info->init, HI_FAILURE);
408
409 hdmi_mutex_lock(evt_info->event_mutex);
410 *thread_id = evt_info->pool[0].ctrl.pool_id;
411 hdmi_mutex_unlock(evt_info->event_mutex);
412
413 return HI_SUCCESS;
414 }
415
416