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);