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 "hdf_device.h"
10 #include "hdf_base.h"
11 #include "hdf_device_node.h"
12 #include "hdf_device_token.h"
13 #include "hdf_log.h"
14 #include "hdf_object_manager.h"
15 #include "osal_mem.h"
16 
17 #define HDF_LOG_TAG hdf_device
18 
19 // device node id less than 129 is configured in hcs, dynamic allocation ID starts from 129
20 #define DYNAMIC_ALLOC_ID 129
21 
UpdateDeivceNodeIdIndex(struct HdfDevice * device,devid_t nodeDevid)22 static void UpdateDeivceNodeIdIndex(struct HdfDevice *device, devid_t nodeDevid)
23 {
24     if (device->devidIndex < DEVNODEID(nodeDevid)) {
25         device->devidIndex = DEVNODEID(nodeDevid);
26     }
27 }
28 
FindUsableDevNodeId(struct HdfDevice * device)29 static devid_t FindUsableDevNodeId(struct HdfDevice *device)
30 {
31     uint16_t nodeId = DYNAMIC_ALLOC_ID;
32     bool find = false;
33     struct HdfDeviceNode *devNode = NULL;
34     for (; nodeId <= device->devidIndex; nodeId++) {
35         find = false;
36         DLIST_FOR_EACH_ENTRY(devNode, &device->devNodes, struct HdfDeviceNode, entry) {
37             if (DEVNODEID(devNode->devId) == nodeId) {
38                 find = true;
39                 break;
40             }
41         }
42         if (!find) {
43             return nodeId;
44         }
45     }
46     return nodeId;
47 }
48 
AcquireNodeDeivceId(struct HdfDevice * device,devid_t * devid)49 static int AcquireNodeDeivceId(struct HdfDevice *device, devid_t *devid)
50 {
51     devid_t nodeId;
52     devid_t usableId;
53     if (device->devidIndex >= DEVNODEID_MASK) {
54         return HDF_FAILURE;
55     }
56 
57     if (device->devidIndex < DYNAMIC_ALLOC_ID) {
58         device->devidIndex = DYNAMIC_ALLOC_ID;
59         nodeId = device->devidIndex;
60     } else {
61         usableId = FindUsableDevNodeId(device);
62         if (usableId <= device->devidIndex) {
63             nodeId = usableId;
64         } else {
65             device->devidIndex++;
66             nodeId = device->devidIndex;
67         }
68     }
69 
70     if (devid == NULL) {
71         HDF_LOGE("params invalid *devid");
72         return HDF_ERR_INVALID_PARAM;
73     }
74     *devid = MK_DEVID(HOSTID(device->deviceId), DEVICEID(device->deviceId), nodeId);
75 
76     return HDF_SUCCESS;
77 }
78 
HdfDeviceAttach(struct IHdfDevice * devInst,struct HdfDeviceNode * devNode)79 static int HdfDeviceAttach(struct IHdfDevice *devInst, struct HdfDeviceNode *devNode)
80 {
81     int ret;
82     struct HdfDevice *device = (struct HdfDevice *)devInst;
83     struct IDeviceNode *nodeIf = (struct IDeviceNode *)devNode;
84 
85     if (device == NULL || nodeIf == NULL || nodeIf->LaunchNode == NULL) {
86         HDF_LOGE("failed to attach device, input params invalid");
87         return HDF_ERR_INVALID_PARAM;
88     }
89 
90     // for dynamic added device node, assign device id here
91     if (devNode->devId == 0 && AcquireNodeDeivceId(device, &devNode->devId) != HDF_SUCCESS) {
92         HDF_LOGE("failed to attach device, invalid device id");
93         return HDF_ERR_INVALID_PARAM;
94     }
95     devNode->token->devid = devNode->devId;
96     ret = nodeIf->LaunchNode(devNode);
97     if (ret == HDF_SUCCESS) {
98         DListInsertTail(&devNode->entry, &device->devNodes);
99         UpdateDeivceNodeIdIndex(device, devNode->devId);
100     }
101 
102     return ret;
103 }
104 
HdfDeviceDetach(struct IHdfDevice * devInst,struct HdfDeviceNode * devNode)105 int HdfDeviceDetach(struct IHdfDevice *devInst, struct HdfDeviceNode *devNode)
106 {
107     struct HdfDevice *device = NULL;
108     if (devInst == NULL || devNode == NULL) {
109         return HDF_ERR_INVALID_PARAM;
110     }
111 
112     device = CONTAINER_OF(devInst, struct HdfDevice, super);
113     if (DEVICEID(device->deviceId) != DEVICEID(devNode->devId)) {
114         HDF_LOGE("%{public}s: device detach unknown devnode ",
115             __func__);
116         return HDF_DEV_ERR_NO_DEVICE;
117     }
118 
119     if (devNode->entry.next != NULL) {
120         DListRemove(&devNode->entry);
121     }
122     if (devNode->super.UnlaunchNode != NULL) {
123         devNode->super.UnlaunchNode(devNode);
124     }
125 
126     return HDF_SUCCESS;
127 }
128 
HdfDeviceGetDeviceNode(struct IHdfDevice * device,devid_t devid)129 static struct HdfDeviceNode *HdfDeviceGetDeviceNode(struct IHdfDevice *device, devid_t devid)
130 {
131     struct HdfDeviceNode *devNode = NULL;
132     struct HdfDevice *dev = CONTAINER_OF(device, struct HdfDevice, super);
133     DLIST_FOR_EACH_ENTRY(devNode, &dev->devNodes, struct HdfDeviceNode, entry) {
134         if (devNode->devId == devid) {
135             return devNode;
136         };
137     }
138     return NULL;
139 }
140 
HdfDeviceDetachWithDevid(struct IHdfDevice * device,devid_t devid)141 static int HdfDeviceDetachWithDevid(struct IHdfDevice *device, devid_t devid)
142 {
143     struct HdfDevice *dev = CONTAINER_OF(device, struct HdfDevice, super);
144     (void)dev;
145     struct HdfDeviceNode *devNode = HdfDeviceGetDeviceNode(device, devid);
146     if (devNode == NULL) {
147         HDF_LOGE("devNode is NULL");
148         return HDF_DEV_ERR_NO_DEVICE;
149     }
150 
151     return HdfDeviceDetach(device, devNode);
152 }
153 
HdfDeviceConstruct(struct HdfDevice * device)154 void HdfDeviceConstruct(struct HdfDevice *device)
155 {
156     device->super.Attach = HdfDeviceAttach;
157     device->super.Detach = HdfDeviceDetach;
158     device->super.DetachWithDevid = HdfDeviceDetachWithDevid;
159     device->super.GetDeviceNode = HdfDeviceGetDeviceNode;
160 
161     DListHeadInit(&device->devNodes);
162 }
163 
HdfDeviceDestruct(struct HdfDevice * device)164 void HdfDeviceDestruct(struct HdfDevice *device)
165 {
166     struct HdfDeviceNode *devNode = NULL;
167     struct HdfDeviceNode *tmp = NULL;
168     DLIST_FOR_EACH_ENTRY_SAFE(devNode, tmp, &device->devNodes, struct HdfDeviceNode, entry) {
169         HdfDeviceNodeFreeInstance(devNode);
170     }
171     DListHeadInit(&device->devNodes);
172 }
173 
HdfDeviceCreate(void)174 struct HdfObject *HdfDeviceCreate(void)
175 {
176     struct HdfDevice *device = (struct HdfDevice *)OsalMemCalloc(sizeof(struct HdfDevice));
177     if (device != NULL) {
178         HdfDeviceConstruct(device);
179     }
180     return (struct HdfObject *)device;
181 }
182 
HdfDeviceRelease(struct HdfObject * object)183 void HdfDeviceRelease(struct HdfObject *object)
184 {
185     struct HdfDevice *device = (struct HdfDevice *)object;
186     if (device != NULL) {
187         HdfDeviceDestruct(device);
188         OsalMemFree(device);
189     }
190 }
191 
HdfDeviceNewInstance(void)192 struct HdfDevice *HdfDeviceNewInstance(void)
193 {
194     return (struct HdfDevice *)HdfObjectManagerGetObject(HDF_OBJECT_ID_DEVICE);
195 }
196 
HdfDeviceFreeInstance(struct HdfDevice * device)197 void HdfDeviceFreeInstance(struct HdfDevice *device)
198 {
199     if (device != NULL) {
200         HdfObjectManagerFreeObject(&device->super.object);
201     }
202 }
203