• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include "platform_event.h"
10 #include "hdf_dlist.h"
11 #include "osal_mem.h"
12 #include "osal_sem.h"
13 #include "platform_errno.h"
14 #include "platform_log.h"
15 
16 #ifdef __cplusplus
17 #if __cplusplus
18 extern "C" {
19 #endif
20 #endif /* __cplusplus */
21 
22 struct PlatformEventWaiter {
23     struct DListHead node;
24     struct OsalSem sem;
25     uint32_t mask;
26     uint32_t mode;
27     void *data;
28     int32_t (*cb)(struct PlatformEventWaiter *waiter, int32_t events);
29 };
30 
PlatformEventInit(struct PlatformEvent * pe)31 int32_t PlatformEventInit(struct PlatformEvent *pe)
32 {
33     if (pe == NULL) {
34         return HDF_ERR_INVALID_OBJECT;
35     }
36     pe->eventsWord = 0;
37     pe->waiterCnt = 0;
38     DListHeadInit(&pe->waiters);
39     (void)OsalSpinInit(&pe->spin);
40     (void)OsalSemInit(&pe->sem, 0);
41     return HDF_SUCCESS;
42 }
43 
PlatformEventLock(struct PlatformEvent * pe)44 static void PlatformEventLock(struct PlatformEvent *pe)
45 {
46     (void)OsalSpinLockIrqSave(&pe->spin, &pe->irqSave);
47 }
48 
PlatformEventUnlock(struct PlatformEvent * pe)49 static void PlatformEventUnlock(struct PlatformEvent *pe)
50 {
51     (void)OsalSpinUnlockIrqRestore(&pe->spin, &pe->irqSave);
52 }
53 
PlatformEventClearWaiters(struct PlatformEvent * pe)54 static void PlatformEventClearWaiters(struct PlatformEvent *pe)
55 {
56     struct PlatformEventWaiter *waiter = NULL;
57     struct PlatformEventWaiter *tmp = NULL;
58 
59     PlatformEventLock(pe);
60     DLIST_FOR_EACH_ENTRY_SAFE(waiter, tmp, &pe->waiters, struct PlatformEventWaiter, node) {
61         DListRemove(&waiter->node);
62         if ((waiter->mode & PLAT_EVENT_MODE_ASYNC) != 0) {
63             OsalMemFree(waiter);
64         }
65     }
66     PlatformEventUnlock(pe);
67 }
68 
PlatformEventUninit(struct PlatformEvent * pe)69 int32_t PlatformEventUninit(struct PlatformEvent *pe)
70 {
71     if (pe == NULL) {
72         return HDF_ERR_INVALID_OBJECT;
73     }
74     PlatformEventClearWaiters(pe);
75     (void)OsalSemDestroy(&pe->sem);
76     (void)OsalSpinDestroy(&pe->spin);
77     return HDF_SUCCESS;
78 }
79 
PlatformEventPost(struct PlatformEvent * pe,uint32_t events)80 int32_t PlatformEventPost(struct PlatformEvent *pe, uint32_t events)
81 {
82     int32_t ret;
83     uint32_t masked;
84     struct PlatformEventWaiter *waiter = NULL;
85     struct PlatformEventWaiter *pos = NULL;
86     struct PlatformEventWaiter *tmp = NULL;
87 
88     if (pe == NULL) {
89         return HDF_ERR_INVALID_OBJECT;
90     }
91     if (events == 0) {
92         return HDF_ERR_INVALID_PARAM;
93     }
94 
95     PlatformEventLock(pe);
96     pe->eventsWord |= events;
97     DLIST_FOR_EACH_ENTRY_SAFE(pos, tmp, &pe->waiters, struct PlatformEventWaiter, node) {
98         if (((pos->mode & PLAT_EVENT_MODE_AND) == 0) &&
99             ((pe->eventsWord & pos->mask) != 0)) {
100             waiter = pos;
101             break;
102         }
103         if (((pos->mode & PLAT_EVENT_MODE_AND) != 0) &&
104             ((pe->eventsWord & pos->mask) == pos->mask)) {
105             waiter = pos;
106             break;
107         }
108     }
109     if (waiter != NULL) {
110         masked = pe->eventsWord & waiter->mask;
111         if ((waiter->mode & PLAT_EVENT_MODE_ASYNC) != 0) {
112             pe->eventsWord &= ~masked;
113         } else {
114             DListRemove(&waiter->node);
115         }
116     }
117     PlatformEventUnlock(pe);
118 
119     if (waiter == NULL) {
120         return HDF_SUCCESS;
121     }
122 
123     if ((waiter->mode & PLAT_EVENT_MODE_ASYNC) == 0) {
124         ret = OsalSemPost(&waiter->sem);
125     } else if (waiter->cb != NULL) {
126         ret = waiter->cb(waiter, masked);
127     } else {
128         ret = HDF_ERR_INVALID_PARAM;
129     }
130 
131     return ret;
132 }
133 
PlatformEventRead(struct PlatformEvent * pe,uint32_t * events,uint32_t mask,int32_t mode)134 static int32_t PlatformEventRead(struct PlatformEvent *pe, uint32_t *events, uint32_t mask, int32_t mode)
135 {
136     uint32_t masked = 0;
137 
138     if (events == NULL || mask == 0) {
139         return HDF_ERR_INVALID_PARAM;
140     }
141     PlatformEventLock(pe);
142     if (((uint32_t)mode & (uint32_t)PLAT_EVENT_MODE_AND) == 0) {
143         if ((pe->eventsWord & mask) != 0) {
144             masked = pe->eventsWord & mask;
145         }
146     } else {
147         if ((pe->eventsWord & mask) == mask) {
148             masked = pe->eventsWord & mask;
149         }
150     }
151     pe->eventsWord &= ~masked; // clear the bits default
152     PlatformEventUnlock(pe);
153 
154     *events = masked;
155     return HDF_SUCCESS;
156 }
157 
PlatformEventReadSlowlly(struct PlatformEvent * pe,uint32_t * events,uint32_t mask,int32_t mode,uint32_t tms)158 static int32_t PlatformEventReadSlowlly(struct PlatformEvent *pe,
159     uint32_t *events, uint32_t mask, int32_t mode, uint32_t tms)
160 {
161     int32_t ret;
162     struct PlatformEventWaiter waiter;
163 
164     waiter.mask = mask;
165     waiter.mode = (uint32_t)mode & (uint32_t)(~PLAT_EVENT_MODE_ASYNC);
166     (void)OsalSemInit(&waiter.sem, 0);
167     DListHeadInit(&waiter.node);
168 
169     PlatformEventLock(pe);
170     DListInsertTail(&waiter.node, &pe->waiters);
171     PlatformEventUnlock(pe);
172 
173     ret = OsalSemWait(&waiter.sem, tms);
174     if (ret == HDF_SUCCESS) {
175         (void)OsalSemDestroy(&waiter.sem);
176         return PlatformEventRead(pe, events, mask, mode);
177     }
178 
179     PlatformEventLock(pe);
180     // the waiter may be still in the list, we need to check...
181     if (waiter.node.next != NULL && !DListIsEmpty(&waiter.node)) {
182         DListRemove(&waiter.node);
183     }
184     PlatformEventUnlock(pe);
185 
186     (void)OsalSemDestroy(&waiter.sem);
187     return ret;
188 }
189 
PlatformEventWait(struct PlatformEvent * pe,uint32_t mask,int32_t mode,uint32_t tms,uint32_t * events)190 int32_t PlatformEventWait(struct PlatformEvent *pe, uint32_t mask, int32_t mode, uint32_t tms, uint32_t *events)
191 {
192     int32_t ret;
193     uint32_t eventsRead;
194 
195     if (pe == NULL) {
196         return HDF_ERR_INVALID_OBJECT;
197     }
198     if (events == NULL || mask == 0) {
199         return HDF_ERR_INVALID_PARAM;
200     }
201 
202     ret = PlatformEventRead(pe, &eventsRead, mask, mode);
203     if (ret != HDF_SUCCESS) {
204         return ret;
205     }
206 
207     if (eventsRead != 0) {
208         *events = eventsRead;
209         return HDF_SUCCESS;
210     }
211 
212     if (tms == 0) {
213         return HDF_PLT_ERR_NO_DATA;
214     }
215 
216     return PlatformEventReadSlowlly(pe, events, mask, mode, tms);
217 }
218 
PlatformEventAsyncCallback(struct PlatformEventWaiter * waiter,int32_t events)219 static int32_t PlatformEventAsyncCallback(struct PlatformEventWaiter *waiter, int32_t events)
220 {
221     struct PlatformEventListener *listener = (struct PlatformEventListener *)waiter->data;
222 
223     if (listener == NULL) {
224         return HDF_ERR_INVALID_PARAM;
225     }
226 
227     // gona do it in thread context later ...
228     return listener->cb(listener, (uint32_t)events & listener->mask);
229 }
230 
PlatformEventListen(struct PlatformEvent * pe,const struct PlatformEventListener * listener)231 int32_t PlatformEventListen(struct PlatformEvent *pe, const struct PlatformEventListener *listener)
232 {
233     struct PlatformEventWaiter *waiter = NULL;
234 
235     if (pe == NULL || listener == NULL) {
236         return HDF_ERR_INVALID_OBJECT;
237     }
238     if (listener->mask == 0 || listener->cb == NULL) {
239         return HDF_ERR_INVALID_PARAM;
240     }
241 
242     waiter = (struct PlatformEventWaiter *)OsalMemCalloc(sizeof(*waiter));
243     if (waiter == NULL) {
244         return HDF_ERR_MALLOC_FAIL;
245     }
246     waiter->mask = listener->mask;
247     waiter->data = (void *)listener;
248     waiter->mode = PLAT_EVENT_MODE_ASYNC;
249     waiter->cb = PlatformEventAsyncCallback;
250 
251     PlatformEventLock(pe);
252     DListHeadInit(&waiter->node);
253     DListInsertTail(&waiter->node, &pe->waiters);
254     PlatformEventUnlock(pe);
255 
256     return HDF_SUCCESS;
257 }
258 
PlatformEventUnlisten(struct PlatformEvent * pe,const struct PlatformEventListener * listener)259 void PlatformEventUnlisten(struct PlatformEvent *pe, const struct PlatformEventListener *listener)
260 {
261     struct PlatformEventWaiter *waiter = NULL;
262     struct PlatformEventWaiter *tmp = NULL;
263 
264     if (pe == NULL || listener == NULL) {
265         return;
266     }
267 
268     PlatformEventLock(pe);
269     DLIST_FOR_EACH_ENTRY_SAFE(waiter, tmp, &pe->waiters, struct PlatformEventWaiter, node) {
270         if ((waiter->mode & PLAT_EVENT_MODE_ASYNC) == 0) {
271             continue;
272         }
273         if (waiter->data == (void *)listener) {
274             DListRemove(&waiter->node);
275             OsalMemFree(waiter);
276             break;
277         }
278     }
279     PlatformEventUnlock(pe);
280 }
281 
282 #ifdef __cplusplus
283 #if __cplusplus
284 }
285 #endif
286 #endif /* __cplusplus */
287