1 /*
2 *
3 * hdf_kevent.c
4 *
5 * HDF kevent implement for linux
6 *
7 * Copyright (c) 2022 Huawei Device Co., Ltd.
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20 #include <linux/completion.h>
21 #include <linux/fb.h>
22 #include <linux/notifier.h>
23 #include <linux/suspend.h>
24
25 #include "devmgr_service_clnt.h"
26 #include "hdf_device_desc.h"
27 #include "hdf_dlist.h"
28 #include "hdf_log.h"
29 #include "hdf_power_state.h"
30 #include "hdf_sbuf.h"
31 #include "osal_mem.h"
32 #include "osal_mutex.h"
33 #include "osal_sysevent.h"
34
35 #define HDF_LOG_TAG kevent
36
37 #define EVENT_TIMEOUT_JIFFIES 5
38 #define EVENT_DEFAULT_SIZE 64
39 #define KEVENT_COMPLETE_EVENT 1
40
41 struct HdfKeventWait {
42 struct completion comp;
43 struct DListHead listNode;
44 uint32_t waitCount;
45 };
46
47 struct HdfKeventClient {
48 struct HdfDeviceIoClient *ioClient;
49 struct DListHead listNode;
50 };
51
52 struct HdfKeventModule {
53 struct HdfDeviceObject *devObj;
54 struct notifier_block keventPmNotifier;
55 struct notifier_block fbNotifier;
56 struct DListHead waitList;
57 struct OsalMutex mutex;
58 struct OsalMutex clientMutex;
59 struct DListHead clientList;
60 int32_t clientCount;
61 };
62
63 static struct HdfKeventModule *g_keventModule = NULL;
64
HdfKeventWaitAlloc(void)65 static struct HdfKeventWait *HdfKeventWaitAlloc(void)
66 {
67 struct HdfKeventWait *wait = OsalMemAlloc(sizeof(struct HdfKeventWait));
68 if (wait != NULL) {
69 init_completion(&wait->comp);
70 }
71
72 return wait;
73 }
74
HdfKeventWaitFree(struct HdfKeventWait * wait)75 static void HdfKeventWaitFree(struct HdfKeventWait *wait)
76 {
77 if (wait != NULL) {
78 OsalMemFree(wait);
79 }
80 }
81
PrepareEvent(struct HdfKeventWait ** wait,uint64_t class,int32_t eventId,const char * content,bool sync)82 static struct HdfSBuf *PrepareEvent(
83 struct HdfKeventWait **wait, uint64_t class, int32_t eventId, const char *content, bool sync)
84 {
85 struct HdfSBuf *eventBuf = NULL;
86 struct HdfSysEvent sysEvent;
87 struct HdfKeventWait *eventWait = NULL;
88
89 eventBuf = HdfSbufObtain(EVENT_DEFAULT_SIZE);
90 if (eventBuf == NULL) {
91 HDF_LOGE("%s: failed to obtain sbuf", __func__);
92 return NULL;
93 }
94
95 sysEvent.eventClass = class;
96 sysEvent.eventid = eventId;
97 sysEvent.syncToken = 0;
98
99 if (sync) {
100 eventWait = HdfKeventWaitAlloc();
101 if (eventWait == NULL) {
102 HdfSbufRecycle(eventBuf);
103 return NULL;
104 }
105 sysEvent.syncToken = (uint64_t)eventWait;
106 }
107
108 if (!HdfSbufWriteBuffer(eventBuf, &sysEvent, sizeof(sysEvent))) {
109 HdfSbufRecycle(eventBuf);
110 return NULL;
111 }
112
113 if (!HdfSbufWriteString(eventBuf, content)) {
114 HdfSbufRecycle(eventBuf);
115 return NULL;
116 }
117
118 *wait = eventWait;
119 return eventBuf;
120 }
121
SendKevent(struct HdfKeventModule * keventModule,uint16_t class,int32_t event,const char * content,bool sync)122 static int SendKevent(
123 struct HdfKeventModule *keventModule, uint16_t class, int32_t event, const char *content, bool sync)
124 {
125 struct HdfSBuf *eventBuf = NULL;
126 struct HdfKeventWait *wait = NULL;
127 struct HdfKeventClient *client = NULL;
128 int ret;
129
130 if (keventModule->clientCount <= 0) {
131 return 0;
132 }
133
134 eventBuf = PrepareEvent(&wait, class, event, content, sync);
135 if (eventBuf == NULL) {
136 return HDF_FAILURE;
137 }
138
139 OsalMutexLock(&keventModule->mutex);
140 if (sync) {
141 DListInsertTail(&wait->listNode, &keventModule->waitList);
142 }
143
144 OsalMutexLock(&keventModule->clientMutex);
145 if (sync) {
146 wait->waitCount = keventModule->clientCount;
147 }
148
149 DLIST_FOR_EACH_ENTRY(client, &keventModule->clientList, struct HdfKeventClient, listNode) {
150 ret = HdfDeviceSendEventToClient(client->ioClient, HDF_SYSEVENT, eventBuf);
151 if (ret) {
152 HDF_LOGE("%s: failed to send device event, %d", __func__, ret);
153 }
154 }
155 OsalMutexUnlock(&keventModule->clientMutex);
156
157 if (sync) {
158 OsalMutexUnlock(&keventModule->mutex);
159 if (wait_for_completion_timeout(&wait->comp, EVENT_TIMEOUT_JIFFIES * HZ) == 0) {
160 HDF_LOGE("%s:send kevent timeout, class=%d, event=%d", __func__, class, event);
161 ret = HDF_ERR_TIMEOUT;
162 }
163
164 OsalMutexLock(&keventModule->mutex);
165 DListRemove(&wait->listNode);
166 HdfKeventWaitFree(wait);
167 }
168
169 OsalMutexUnlock(&keventModule->mutex);
170 HdfSbufRecycle(eventBuf);
171 return ret;
172 }
173
HdfSysEventSend(uint64_t eventClass,uint32_t event,const char * content,bool sync)174 int32_t HdfSysEventSend(uint64_t eventClass, uint32_t event, const char *content, bool sync)
175 {
176 struct HdfKeventModule *keventmodule = g_keventModule;
177 if (keventmodule == NULL) {
178 return HDF_DEV_ERR_OP;
179 }
180
181 return SendKevent(keventmodule, eventClass, event, content, sync);
182 }
183
KernalSpacePmNotify(int32_t powerEvent)184 static int32_t KernalSpacePmNotify(int32_t powerEvent)
185 {
186 uint32_t pmStatus = POWER_STATE_MAX;
187 struct DevmgrServiceClnt *devmgrClnt = NULL;
188
189 switch (powerEvent) {
190 case KEVENT_POWER_SUSPEND:
191 pmStatus = POWER_STATE_SUSPEND;
192 break;
193 case KEVENT_POWER_DISPLAY_OFF:
194 pmStatus = POWER_STATE_DOZE_SUSPEND;
195 break;
196 case KEVENT_POWER_RESUME:
197 pmStatus = POWER_STATE_RESUME;
198 break;
199 case KEVENT_POWER_DISPLAY_ON:
200 pmStatus = POWER_STATE_DOZE_RESUME;
201 break;
202 default:
203 return HDF_ERR_INVALID_PARAM;
204 }
205
206 devmgrClnt = DevmgrServiceClntGetInstance();
207 if (devmgrClnt == NULL || devmgrClnt->devMgrSvcIf == NULL) {
208 return HDF_FAILURE;
209 }
210
211 return devmgrClnt->devMgrSvcIf->PowerStateChange(devmgrClnt->devMgrSvcIf, pmStatus);
212 }
213
KeventPmNotifierFn(struct notifier_block * nb,unsigned long action,void * dummy)214 static int32_t KeventPmNotifierFn(struct notifier_block *nb, unsigned long action, void *dummy)
215 {
216 struct HdfKeventModule *keventModule = NULL;
217 int32_t powerEvent;
218 bool sync = false;
219 int ret = 0;
220
221 (void)dummy;
222 keventModule = CONTAINER_OF(nb, struct HdfKeventModule, keventPmNotifier);
223 HDF_LOGI("%s:action=%d", __func__, action);
224 switch (action) {
225 case PM_SUSPEND_PREPARE:
226 HDF_LOGI("%s:receive suspend event", __func__);
227 powerEvent = KEVENT_POWER_SUSPEND;
228 sync = true;
229 break;
230 case PM_POST_SUSPEND:
231 HDF_LOGI("%s:receive resume event", __func__);
232 powerEvent = KEVENT_POWER_RESUME;
233 break;
234 default:
235 return 0;
236 }
237
238 ret = SendKevent(keventModule, HDF_SYSEVENT_CLASS_POWER, powerEvent, NULL, sync);
239 if (ret != HDF_SUCCESS) {
240 HDF_LOGE("%s: failed to notify userspace pm status", __func__);
241 }
242
243 return KernalSpacePmNotify(powerEvent);
244 }
245
KeventFbNotifierFn(struct notifier_block * nb,unsigned long event,void * data)246 static int32_t KeventFbNotifierFn(struct notifier_block *nb, unsigned long event, void *data)
247 {
248 int *blank = NULL;
249 struct fb_event *fbEvent = data;
250 struct HdfKeventModule *keventModule = NULL;
251 int32_t powerEvent;
252 bool sync = false;
253 int ret = 0;
254
255 if (event != FB_EVENT_BLANK) {
256 return 0;
257 }
258
259 if (fbEvent == NULL || fbEvent->data == NULL) {
260 return 0;
261 }
262
263 keventModule = CONTAINER_OF(nb, struct HdfKeventModule, fbNotifier);
264 blank = fbEvent->data;
265
266 HDF_LOGI("%s:blank=%d", __func__, *blank);
267 switch (*blank) {
268 case FB_BLANK_UNBLANK:
269 HDF_LOGI("%s:receive display on event", __func__);
270 powerEvent = KEVENT_POWER_DISPLAY_ON;
271 break;
272 default:
273 HDF_LOGI("%s:receive display off event", __func__);
274 powerEvent = KEVENT_POWER_DISPLAY_OFF;
275 sync = true;
276 break;
277 }
278
279 ret = SendKevent(keventModule, HDF_SYSEVENT_CLASS_POWER, powerEvent, NULL, sync);
280 if (ret != HDF_SUCCESS) {
281 HDF_LOGE("%s: failed to notify userspace pm status", __func__);
282 }
283
284 return KernalSpacePmNotify(powerEvent);
285 }
286
CompleteKevent(struct HdfKeventModule * keventModule,struct HdfSBuf * tokenBuffer)287 void CompleteKevent(struct HdfKeventModule *keventModule, struct HdfSBuf *tokenBuffer)
288 {
289 uint64_t token = 0;
290 struct HdfKeventWait *wait = NULL;
291
292 if (tokenBuffer == NULL || !HdfSbufReadUint64(tokenBuffer, &token)) {
293 return;
294 }
295
296 OsalMutexLock(&keventModule->mutex);
297 DLIST_FOR_EACH_ENTRY(wait, &keventModule->waitList, struct HdfKeventWait, listNode) {
298 if (token == (uint64_t)wait) {
299 wait->waitCount--;
300 if (wait->waitCount == 0) {
301 complete(&wait->comp);
302 }
303 }
304 }
305 OsalMutexUnlock(&keventModule->mutex);
306 }
307
HdfKeventIoServiceDispatch(struct HdfDeviceIoClient * client,int id,struct HdfSBuf * data,struct HdfSBuf * reply)308 static int32_t HdfKeventIoServiceDispatch(
309 struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, struct HdfSBuf *reply)
310 {
311 struct HdfKeventModule *keventModule;
312 (void)reply;
313
314 keventModule = (struct HdfKeventModule *)client->device->priv;
315 if (keventModule == NULL) {
316 return HDF_ERR_INVALID_PARAM;
317 }
318
319 switch (id) {
320 case KEVENT_COMPLETE_EVENT: {
321 CompleteKevent(keventModule, data);
322 break;
323 }
324 default:
325 break;
326 }
327
328 return 0;
329 }
330
HdfKeventDriverOpen(struct HdfDeviceIoClient * client)331 static int32_t HdfKeventDriverOpen(struct HdfDeviceIoClient *client)
332 {
333 struct HdfKeventModule *keventModule = NULL;
334 struct HdfKeventClient *kClient = NULL;
335
336 if (client == NULL || client->device == NULL || client->device->priv == NULL) {
337 return HDF_ERR_INVALID_PARAM;
338 }
339
340 keventModule = (struct HdfKeventModule *)client->device->priv;
341 kClient = OsalMemCalloc(sizeof(struct HdfKeventClient));
342 if (kClient == NULL) {
343 return HDF_ERR_MALLOC_FAIL;
344 }
345 kClient->ioClient = client;
346 client->priv = kClient;
347
348 OsalMutexLock(&keventModule->clientMutex);
349 DListInsertTail(&kClient->listNode, &keventModule->clientList);
350 keventModule->clientCount++;
351 OsalMutexUnlock(&keventModule->clientMutex);
352
353 HDF_LOGI("%s:kevent usecount=%d", __func__, keventModule->clientCount);
354 return 0;
355 }
356
HdfKeventDriverClose(struct HdfDeviceIoClient * client)357 static void HdfKeventDriverClose(struct HdfDeviceIoClient *client)
358 {
359 struct HdfKeventClient *kClient = NULL;
360 struct HdfKeventModule *keventModule;
361
362 keventModule = (struct HdfKeventModule *)client->device->priv;
363 if (keventModule == NULL) {
364 return;
365 }
366
367 kClient = (struct HdfKeventClient *)client->priv;
368 if (kClient == NULL) {
369 return;
370 }
371
372 OsalMutexLock(&keventModule->clientMutex);
373 DListRemove(&kClient->listNode);
374 keventModule->clientCount--;
375 OsalMemFree(kClient);
376 client->priv = NULL;
377 OsalMutexUnlock(&keventModule->clientMutex);
378
379 HDF_LOGI("%s:kevnet usecount=%d", __func__, keventModule->clientCount);
380 }
381
HdfKeventDriverRelease(struct HdfDeviceObject * object)382 static void HdfKeventDriverRelease(struct HdfDeviceObject *object)
383 {
384 struct HdfKeventModule *keventModule = (struct HdfKeventModule *)object->priv;
385 if (keventModule == NULL) {
386 return;
387 }
388
389 unregister_pm_notifier(&keventModule->keventPmNotifier);
390 fb_unregister_client(&keventModule->keventPmNotifier);
391 OsalMutexDestroy(&keventModule->mutex);
392 OsalMutexDestroy(&keventModule->clientMutex);
393 OsalMemFree(keventModule);
394 object->priv = NULL;
395 return;
396 }
397
HdfKeventDriverBind(struct HdfDeviceObject * dev)398 static int32_t HdfKeventDriverBind(struct HdfDeviceObject *dev)
399 {
400 static struct IDeviceIoService keventService = {
401 .Open = HdfKeventDriverOpen,
402 .Dispatch = HdfKeventIoServiceDispatch,
403 .Release = HdfKeventDriverClose,
404 };
405 struct HdfKeventModule *keventModule = NULL;
406 if (dev == NULL) {
407 return HDF_ERR_INVALID_PARAM;
408 }
409
410 keventModule = (struct HdfKeventModule *)OsalMemCalloc(sizeof(struct HdfKeventModule));
411 if (keventModule == NULL) {
412 return HDF_ERR_MALLOC_FAIL;
413 }
414
415 if (OsalMutexInit(&keventModule->mutex) != HDF_SUCCESS) {
416 OsalMemFree(keventModule);
417 return HDF_FAILURE;
418 }
419
420 if (OsalMutexInit(&keventModule->clientMutex) != HDF_SUCCESS) {
421 OsalMutexDestroy(&keventModule->mutex);
422 OsalMemFree(keventModule);
423 return HDF_FAILURE;
424 }
425 DListHeadInit(&keventModule->waitList);
426 DListHeadInit(&keventModule->clientList);
427 keventModule->devObj = dev;
428 dev->priv = keventModule;
429 dev->service = &keventService;
430
431 return HDF_SUCCESS;
432 }
433
HdfKeventDriverInit(struct HdfDeviceObject * dev)434 static int32_t HdfKeventDriverInit(struct HdfDeviceObject *dev)
435 {
436 int32_t ret;
437 struct HdfKeventModule *keventModule = (struct HdfKeventModule *)dev->priv;
438
439 keventModule->keventPmNotifier.notifier_call = KeventPmNotifierFn;
440 ret = register_pm_notifier(&keventModule->keventPmNotifier);
441 if (ret != 0) {
442 HDF_LOGE("%s:failed to register pm notifier %d", __func__, ret);
443 } else {
444 HDF_LOGI("%s:register pm notifier success", __func__);
445 }
446
447 keventModule->fbNotifier.notifier_call = KeventFbNotifierFn;
448 ret = fb_register_client(&keventModule->fbNotifier);
449 if (ret != 0) {
450 HDF_LOGE("%s:failed to register fb notifier %d", __func__, ret);
451 unregister_pm_notifier(&keventModule->keventPmNotifier);
452 } else {
453 HDF_LOGI("%s:register fb notifier success", __func__);
454 }
455
456 g_keventModule = keventModule;
457 return ret;
458 }
459
460 static struct HdfDriverEntry g_hdfKeventDriverEntry = {
461 .moduleVersion = 1,
462 .moduleName = "HDF_KEVENT",
463 .Bind = HdfKeventDriverBind,
464 .Init = HdfKeventDriverInit,
465 .Release = HdfKeventDriverRelease,
466 };
467
468 HDF_INIT(g_hdfKeventDriverEntry);
469