1 /*
2  *
3  * hdf_kevent.c
4  *
5  * HDF kevent implement for linux
6  *
7  * Copyright (c) 2022-2023 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     if (*blank == FB_BLANK_UNBLANK) {
268         HDF_LOGI("%s:receive display on event", __func__);
269         powerEvent = KEVENT_POWER_DISPLAY_ON;
270     } else {
271         HDF_LOGI("%s:receive display off event", __func__);
272         powerEvent = KEVENT_POWER_DISPLAY_OFF;
273         sync = true;
274     }
275 
276     ret = SendKevent(keventModule, HDF_SYSEVENT_CLASS_POWER, powerEvent, NULL, sync);
277     if (ret != HDF_SUCCESS) {
278         HDF_LOGE("%s: failed to notify userspace pm status", __func__);
279     }
280 
281     return KernalSpacePmNotify(powerEvent);
282 }
283 
CompleteKevent(struct HdfKeventModule * keventModule,struct HdfSBuf * tokenBuffer)284 void CompleteKevent(struct HdfKeventModule *keventModule, struct HdfSBuf *tokenBuffer)
285 {
286     uint64_t token = 0;
287     struct HdfKeventWait *wait = NULL;
288 
289     if (tokenBuffer == NULL || !HdfSbufReadUint64(tokenBuffer, &token)) {
290         return;
291     }
292 
293     OsalMutexLock(&keventModule->mutex);
294     DLIST_FOR_EACH_ENTRY(wait, &keventModule->waitList, struct HdfKeventWait, listNode) {
295         if (token == (uint64_t)wait) {
296             wait->waitCount--;
297             if (wait->waitCount == 0) {
298                 complete(&wait->comp);
299             }
300         }
301     }
302     OsalMutexUnlock(&keventModule->mutex);
303 }
304 
HdfKeventIoServiceDispatch(struct HdfDeviceIoClient * client,int id,struct HdfSBuf * data,struct HdfSBuf * reply)305 static int32_t HdfKeventIoServiceDispatch(
306     struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, struct HdfSBuf *reply)
307 {
308     struct HdfKeventModule *keventModule;
309     (void)reply;
310 
311     keventModule = (struct HdfKeventModule *)client->device->priv;
312     if (keventModule == NULL) {
313         return HDF_ERR_INVALID_PARAM;
314     }
315 
316     if (id == KEVENT_COMPLETE_EVENT) {
317         CompleteKevent(keventModule, data);
318     }
319 
320     return 0;
321 }
322 
HdfKeventDriverOpen(struct HdfDeviceIoClient * client)323 static int32_t HdfKeventDriverOpen(struct HdfDeviceIoClient *client)
324 {
325     struct HdfKeventModule *keventModule = NULL;
326     struct HdfKeventClient *kClient = NULL;
327 
328     if (client == NULL || client->device == NULL || client->device->priv == NULL) {
329         return HDF_ERR_INVALID_PARAM;
330     }
331 
332     keventModule = (struct HdfKeventModule *)client->device->priv;
333     kClient = OsalMemCalloc(sizeof(struct HdfKeventClient));
334     if (kClient == NULL) {
335         return HDF_ERR_MALLOC_FAIL;
336     }
337     kClient->ioClient = client;
338     client->priv = kClient;
339 
340     OsalMutexLock(&keventModule->clientMutex);
341     DListInsertTail(&kClient->listNode, &keventModule->clientList);
342     keventModule->clientCount++;
343     OsalMutexUnlock(&keventModule->clientMutex);
344 
345     HDF_LOGI("%s:kevent usecount=%d", __func__, keventModule->clientCount);
346     return 0;
347 }
348 
HdfKeventDriverClose(struct HdfDeviceIoClient * client)349 static void HdfKeventDriverClose(struct HdfDeviceIoClient *client)
350 {
351     struct HdfKeventClient *kClient = NULL;
352     struct HdfKeventModule *keventModule;
353 
354     keventModule = (struct HdfKeventModule *)client->device->priv;
355     if (keventModule == NULL) {
356         return;
357     }
358 
359     kClient = (struct HdfKeventClient *)client->priv;
360     if (kClient == NULL) {
361         return;
362     }
363 
364     OsalMutexLock(&keventModule->clientMutex);
365     DListRemove(&kClient->listNode);
366     keventModule->clientCount--;
367     OsalMemFree(kClient);
368     client->priv = NULL;
369     OsalMutexUnlock(&keventModule->clientMutex);
370 
371     HDF_LOGI("%s:kevnet usecount=%d", __func__, keventModule->clientCount);
372 }
373 
HdfKeventDriverRelease(struct HdfDeviceObject * object)374 static void HdfKeventDriverRelease(struct HdfDeviceObject *object)
375 {
376     struct HdfKeventModule *keventModule = (struct HdfKeventModule *)object->priv;
377     if (keventModule == NULL) {
378         return;
379     }
380 
381     unregister_pm_notifier(&keventModule->keventPmNotifier);
382     fb_unregister_client(&keventModule->keventPmNotifier);
383     OsalMutexDestroy(&keventModule->mutex);
384     OsalMutexDestroy(&keventModule->clientMutex);
385     OsalMemFree(keventModule);
386     object->priv = NULL;
387     return;
388 }
389 
HdfKeventDriverBind(struct HdfDeviceObject * dev)390 static int32_t HdfKeventDriverBind(struct HdfDeviceObject *dev)
391 {
392     static struct IDeviceIoService keventService = {
393         .Open = HdfKeventDriverOpen,
394         .Dispatch = HdfKeventIoServiceDispatch,
395         .Release = HdfKeventDriverClose,
396     };
397     struct HdfKeventModule *keventModule = NULL;
398     if (dev == NULL) {
399         return HDF_ERR_INVALID_PARAM;
400     }
401 
402     keventModule = (struct HdfKeventModule *)OsalMemCalloc(sizeof(struct HdfKeventModule));
403     if (keventModule == NULL) {
404         return HDF_ERR_MALLOC_FAIL;
405     }
406 
407     if (OsalMutexInit(&keventModule->mutex) != HDF_SUCCESS) {
408         OsalMemFree(keventModule);
409         return HDF_FAILURE;
410     }
411 
412     if (OsalMutexInit(&keventModule->clientMutex) != HDF_SUCCESS) {
413         OsalMutexDestroy(&keventModule->mutex);
414         OsalMemFree(keventModule);
415         return HDF_FAILURE;
416     }
417     DListHeadInit(&keventModule->waitList);
418     DListHeadInit(&keventModule->clientList);
419     keventModule->devObj = dev;
420     dev->priv = keventModule;
421     dev->service = &keventService;
422 
423     return HDF_SUCCESS;
424 }
425 
HdfKeventDriverInit(struct HdfDeviceObject * dev)426 static int32_t HdfKeventDriverInit(struct HdfDeviceObject *dev)
427 {
428     int32_t ret;
429     struct HdfKeventModule *keventModule = (struct HdfKeventModule *)dev->priv;
430 
431     keventModule->keventPmNotifier.notifier_call = KeventPmNotifierFn;
432     ret = register_pm_notifier(&keventModule->keventPmNotifier);
433     if (ret != 0) {
434         HDF_LOGE("%s:failed to register pm notifier %d", __func__, ret);
435     } else {
436         HDF_LOGI("%s:register pm notifier success", __func__);
437     }
438 
439     keventModule->fbNotifier.notifier_call = KeventFbNotifierFn;
440     ret = fb_register_client(&keventModule->fbNotifier);
441     if (ret != 0) {
442         HDF_LOGE("%s:failed to register fb notifier %d", __func__, ret);
443         unregister_pm_notifier(&keventModule->keventPmNotifier);
444     } else {
445         HDF_LOGI("%s:register fb notifier success", __func__);
446     }
447 
448     g_keventModule = keventModule;
449     return ret;
450 }
451 
452 static struct HdfDriverEntry g_hdfKeventDriverEntry = {
453     .moduleVersion = 1,
454     .moduleName = "HDF_KEVENT",
455     .Bind = HdfKeventDriverBind,
456     .Init = HdfKeventDriverInit,
457     .Release = HdfKeventDriverRelease,
458 };
459 
460 HDF_INIT(g_hdfKeventDriverEntry);
461