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