• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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