1 /*
2 * Copyright (c) 2020-2023 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_manager.h"
10 #include "hdf_log.h"
11 #include "osal_mem.h"
12 #include "osal_sem.h"
13 #include "platform_core.h"
14
15 #define PLATFORM_MANAGER_NAME_DEFAULT "PlatformManagerDefault"
16
PlatformManagerLock(struct PlatformManager * manager)17 static inline void PlatformManagerLock(struct PlatformManager *manager)
18 {
19 (void)OsalSpinLockIrqSave(&manager->device.spin, &manager->device.irqSave);
20 }
21
PlatformManagerUnlock(struct PlatformManager * manager)22 static inline void PlatformManagerUnlock(struct PlatformManager *manager)
23 {
24 (void)OsalSpinUnlockIrqRestore(&manager->device.spin, &manager->device.irqSave);
25 }
26
PlatformManagerInit(struct PlatformManager * manager)27 static int32_t PlatformManagerInit(struct PlatformManager *manager)
28 {
29 int32_t ret;
30
31 DListHeadInit(&manager->devices);
32
33 if ((ret = PlatformDeviceInit(&manager->device)) != HDF_SUCCESS) {
34 PLAT_LOGE("PlatformManagerInit: device init fail!");
35 return ret;
36 }
37
38 manager->add = NULL;
39 manager->del = NULL;
40 return HDF_SUCCESS;
41 }
42
PlatformManagerClearDevice(struct PlatformManager * manager)43 static void PlatformManagerClearDevice(struct PlatformManager *manager)
44 {
45 struct PlatformDevice *tmp = NULL;
46 struct PlatformDevice *pos = NULL;
47
48 if (manager == NULL) {
49 PLAT_LOGE("PlatformManagerClearDevice: manager is null!");
50 return;
51 }
52
53 PlatformManagerLock(manager);
54 DLIST_FOR_EACH_ENTRY_SAFE(pos, tmp, &manager->devices, struct PlatformDevice, node) {
55 DListRemove(&pos->node);
56 PlatformDevicePut(pos); // put the reference hold by manager
57 }
58 PlatformManagerUnlock(manager);
59 }
60
PlatformManagerUninit(struct PlatformManager * manager)61 static void PlatformManagerUninit(struct PlatformManager *manager)
62 {
63 PlatformManagerClearDevice(manager);
64 PlatformDeviceUninit(&manager->device);
65 manager->add = NULL;
66 manager->del = NULL;
67 }
68
PlatformManagerCreate(const char * name,struct PlatformManager ** manager)69 int32_t PlatformManagerCreate(const char *name, struct PlatformManager **manager)
70 {
71 int32_t ret;
72 struct PlatformManager *managerNew = NULL;
73
74 managerNew = (struct PlatformManager *)OsalMemCalloc(sizeof(*managerNew));
75 if (managerNew == NULL) {
76 PLAT_LOGE("PlatformManagerCreate: malloc fail!");
77 return HDF_ERR_MALLOC_FAIL;
78 }
79 managerNew->device.name = name;
80 if ((ret = PlatformManagerInit(managerNew)) != HDF_SUCCESS) {
81 OsalMemFree(managerNew);
82 PLAT_LOGE("PlatformManagerCreate: platform manager init fail!");
83 return ret;
84 }
85 *manager = managerNew;
86 return ret;
87 }
88
PlatformManagerDestroy(struct PlatformManager * manager)89 void PlatformManagerDestroy(struct PlatformManager *manager)
90 {
91 if (manager == NULL) {
92 PLAT_LOGE("PlatformManagerDestroy: manager is null!");
93 return;
94 }
95 PlatformManagerUninit(manager);
96 OsalMemFree(manager);
97 }
98
PlatformManagerGet(int module)99 struct PlatformManager *PlatformManagerGet(int module)
100 {
101 int32_t ret;
102 struct PlatformManager *manager = NULL;
103 struct PlatformModuleInfo *info = NULL;
104
105 info = PlatformModuleInfoGet(module);
106 if (info == NULL) {
107 PLAT_LOGE("PlatformManagerGet: get module(%d) info fail!", module);
108 return NULL;
109 }
110
111 PlatformGlobalLock();
112 if (info->priv == NULL) {
113 ret = PlatformManagerCreate(info->moduleName, &manager);
114 if (ret != HDF_SUCCESS) {
115 PLAT_LOGE("PlatformManagerGet: create manager fail, ret: %d!", ret);
116 } else {
117 info->priv = manager;
118 }
119 } else {
120 manager = (struct PlatformManager *)info->priv;
121 }
122 PlatformGlobalUnlock();
123
124 return manager;
125 }
126
PlatformManagerAddDeviceDefault(struct PlatformManager * manager,struct PlatformDevice * device)127 static int32_t PlatformManagerAddDeviceDefault(struct PlatformManager *manager, struct PlatformDevice *device)
128 {
129 struct PlatformDevice *tmp = NULL;
130 bool repeatId = false;
131 bool repeatName = false;
132
133 DLIST_FOR_EACH_ENTRY(tmp, &manager->devices, struct PlatformDevice, node) {
134 if (device->number == tmp->number) {
135 repeatId = true;
136 PLAT_LOGE("PlatformManagerAddDeviceDefault: device:%s(%d) num repeated in manager:%s!",
137 device->name, device->number, manager->device.name);
138 break;
139 }
140 if (device->name != NULL && device->name == tmp->name) {
141 repeatName = true;
142 PLAT_LOGE("PlatformManagerAddDeviceDefault: device:%s(%d) name repeated in manager:%s!",
143 device->name, device->number, manager->device.name);
144 break;
145 }
146 }
147
148 if (repeatId) {
149 return HDF_PLT_ERR_ID_REPEAT;
150 }
151 if (repeatName) {
152 return HDF_PLT_ERR_NAME_REPEAT;
153 }
154
155 DListInsertTail(&device->node, &manager->devices);
156 return HDF_SUCCESS;
157 }
158
PlatformManagerAddDevice(struct PlatformManager * manager,struct PlatformDevice * device)159 int32_t PlatformManagerAddDevice(struct PlatformManager *manager, struct PlatformDevice *device)
160 {
161 int32_t ret;
162 struct PlatformDevice *pos = NULL;
163
164 if (manager == NULL || device == NULL) {
165 PLAT_LOGE("PlatformManagerAddDevice: manager or device is null!");
166 return HDF_ERR_INVALID_OBJECT;
167 }
168
169 if (PlatformDeviceGet(device) != HDF_SUCCESS) { // keep a reference by manager
170 PLAT_LOGE("PlatformManagerAddDevice: get device fail!");
171 return HDF_PLT_ERR_DEV_GET;
172 }
173
174 PlatformManagerLock(manager);
175 DLIST_FOR_EACH_ENTRY(pos, &manager->devices, struct PlatformDevice, node) {
176 if (pos == device) {
177 PlatformManagerUnlock(manager);
178 PLAT_LOGE("PlatformManagerAddDevice: device:%s(%d) already in manager:%s!",
179 device->name, device->number, manager->device.name);
180 PlatformDevicePut(device);
181 return HDF_PLT_ERR_OBJ_REPEAT;
182 }
183 }
184 if (manager->add != NULL) {
185 ret = manager->add(manager, device);
186 } else {
187 ret = PlatformManagerAddDeviceDefault(manager, device);
188 }
189 PlatformManagerUnlock(manager);
190
191 if (ret == HDF_SUCCESS) {
192 PLAT_LOGD("PlatformManagerAddDevice: add dev:%s(%d) to %s success!",
193 device->name, device->number, manager->device.name);
194 } else {
195 PlatformDevicePut(device);
196 PLAT_LOGE("PlatformManagerAddDevice: add dev:%s(%d) to %s fail, ret:%d!",
197 device->name, device->number, manager->device.name, ret);
198 }
199
200 return ret;
201 }
202
PlatformManagerDelDeviceDefault(const struct PlatformManager * manager,struct PlatformDevice * device)203 static int32_t PlatformManagerDelDeviceDefault(const struct PlatformManager *manager, struct PlatformDevice *device)
204 {
205 if (manager == NULL || device == NULL) {
206 PLAT_LOGE("PlatformManagerDelDeviceDefault: manager or device is null!");
207 return HDF_ERR_INVALID_OBJECT;
208 }
209 if (!DListIsEmpty(&device->node)) {
210 DListRemove(&device->node);
211 } else {
212 PLAT_LOGE("PlatformManagerDelDeviceDefault: device:%s already moved!", device->name);
213 return HDF_ERR_INVALID_PARAM;
214 }
215
216 return HDF_SUCCESS;
217 }
218
PlatformManagerDelDevice(struct PlatformManager * manager,struct PlatformDevice * device)219 int32_t PlatformManagerDelDevice(struct PlatformManager *manager, struct PlatformDevice *device)
220 {
221 int32_t ret;
222 struct PlatformDevice *pos = NULL;
223
224 if (manager == NULL || device == NULL) {
225 PLAT_LOGE("PlatformManagerDelDevice: manager or device is null!");
226 return HDF_ERR_INVALID_OBJECT;
227 }
228
229 PlatformManagerLock(manager);
230 DLIST_FOR_EACH_ENTRY(pos, &manager->devices, struct PlatformDevice, node) {
231 if (pos == device) {
232 break;
233 }
234 }
235 if (pos != device) {
236 PLAT_LOGE("PlatformManagerDelDevice: device:%s(%d) not in manager:%s!",
237 device->name, device->number, manager->device.name);
238 PlatformManagerUnlock(manager);
239 return HDF_PLT_ERR_NO_DEV;
240 }
241 if (manager->del != NULL) {
242 ret = manager->del(manager, device);
243 } else {
244 ret = PlatformManagerDelDeviceDefault(manager, device);
245 }
246 PlatformManagerUnlock(manager);
247
248 if (ret == HDF_SUCCESS) {
249 PlatformDevicePut(device); // put the reference hold by manager
250 PLAT_LOGD("PlatformManagerDelDevice: remove %s(%d) from %s success!",
251 device->name, device->number, manager->device.name);
252 } else {
253 PLAT_LOGE("PlatformManagerDelDevice: remove %s(%d) from %s fail, ret:%d!",
254 device->name, device->number, manager->device.name, ret);
255 }
256 return ret;
257 }
258
PlatformManagerFindDevice(struct PlatformManager * manager,void * data,bool (* match)(struct PlatformDevice * pdevice,void * data))259 struct PlatformDevice *PlatformManagerFindDevice(struct PlatformManager *manager, void *data,
260 bool (*match)(struct PlatformDevice *pdevice, void *data))
261 {
262 struct PlatformDevice *tmp = NULL;
263 struct PlatformDevice *pdevice = NULL;
264
265 if (manager == NULL || match == NULL) {
266 PLAT_LOGE("PlatformManagerFindDevice: manager or match is null!");
267 return NULL;
268 }
269 if (manager->devices.prev == NULL || manager->devices.next == NULL) {
270 PLAT_LOGE("PlatformManagerFindDevice: devices not init!");
271 return NULL;
272 }
273
274 PlatformManagerLock(manager);
275 DLIST_FOR_EACH_ENTRY(tmp, &manager->devices, struct PlatformDevice, node) {
276 if (tmp == NULL || !match(tmp, data)) {
277 continue;
278 }
279 if (PlatformDeviceGet(tmp) == HDF_SUCCESS) {
280 pdevice = tmp;
281 }
282 break;
283 }
284 PlatformManagerUnlock(manager);
285
286 return pdevice;
287 }
288
PlatformDeviceMatchByNumber(struct PlatformDevice * device,void * data)289 static bool PlatformDeviceMatchByNumber(struct PlatformDevice *device, void *data)
290 {
291 uint32_t number = (uint32_t)(uintptr_t)data;
292
293 return (device != NULL && (uint32_t)device->number == number);
294 }
295
PlatformManagerGetDeviceByNumber(struct PlatformManager * manager,uint32_t number)296 struct PlatformDevice *PlatformManagerGetDeviceByNumber(struct PlatformManager *manager, uint32_t number)
297 {
298 if (manager == NULL) {
299 PLAT_LOGE("PlatformManagerGetDeviceByNumber: manager is null!");
300 return NULL;
301 }
302 return PlatformManagerFindDevice(manager, (void *)(uintptr_t)number, PlatformDeviceMatchByNumber);
303 }
304
PlatformDeviceMatchByName(struct PlatformDevice * device,void * data)305 static bool PlatformDeviceMatchByName(struct PlatformDevice *device, void *data)
306 {
307 const char *name = (const char *)data;
308
309 if (name == NULL || device->name == NULL) {
310 PLAT_LOGE("PlatformDeviceMatchByName: name or device->name is null!");
311 return false;
312 }
313
314 return (strcmp(name, device->name) == 0);
315 }
316
PlatformManagerGetDeviceByName(struct PlatformManager * manager,const char * name)317 struct PlatformDevice *PlatformManagerGetDeviceByName(struct PlatformManager *manager, const char *name)
318 {
319 if (manager == NULL) {
320 PLAT_LOGE("PlatformManagerGetDeviceByName: manager is null!");
321 return NULL;
322 }
323 return PlatformManagerFindDevice(manager, (void *)name, PlatformDeviceMatchByName);
324 }
325