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