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