1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <dlfcn.h>
17 #include "hdf_audio_pnp_server.h"
18 #include "audio_uhdf_log.h"
19 #include "hdf_audio_input_event.h"
20 #include "hdf_audio_pnp_uevent.h"
21 #include "hdf_audio_pnp_uevent_hdmi.h"
22 #include "hdf_device_desc.h"
23 #include "hdf_device_object.h"
24 #include "hdf_io_service_if.h"
25 #include "hdf_sbuf.h"
26 #include "hdf_service_status.h"
27 #include "securec.h"
28 #include "servmgr_hdi.h"
29 
30 #define HDF_LOG_TAG             HDF_AUDIO_HOST
31 #define AUDIO_HDI_SERVICE_NAME  "audio_hdi_usb_service"
32 #define AUDIO_TOKEN_SERVER_NAME "ohos.hdi.audio_service"
33 #define AUDIO_PNP_INFO_LEN_MAX  256
34 #define AUDIO_CONTROL           "hdf_audio_control"
35 
36 #define AUDIODRV_CTRL_IOCTRL_ELEM_HDMI 5 // define from adm control stream id
37 
38 struct AudioPnpPriv {
39     void *handle;
40     FfrtAllocBase ffrtAllocBase;
41     FfrtTaskAttrInit ffrtInitAttr;
42     FfrtTaskAttrSetQos ffrtSetQosAttr;
43     FfrtTaskAttrSetName ffrtSetNameAttr;
44     FfrtSubmitBase ffrtSubmitBase;
45 };
46 static struct AudioPnpPriv g_priv;
47 
FfrtExecFunctionWrapper(void * t)48 static void FfrtExecFunctionWrapper(void* t)
49 {
50     FfrtFunction* f = (FfrtFunction*)t;
51     if (f == NULL) {
52         return;
53     }
54     if (f->func) {
55         f->func(f->arg);
56     }
57 }
58 
FfrtDestroyFunctionWrapper(void * t)59 static void FfrtDestroyFunctionWrapper(void* t)
60 {
61     FfrtFunction* f = (FfrtFunction*)t;
62     if (f == NULL) {
63         return;
64     }
65     if (f->afterFunc) {
66         f->afterFunc(f->arg);
67     }
68 }
69 
FfrtCreateFunctionWrapper(const FfrtFunctionT func,const FfrtFunctionT afterFunc,void * arg)70 FfrtFunctionHeader* FfrtCreateFunctionWrapper(const FfrtFunctionT func,
71     const FfrtFunctionT afterFunc, void* arg)
72 {
73     if (sizeof(FfrtFunction) > FFRT_AUTO_MANAGED_FUNCTION_STORAGE_SIZE) {
74         AUDIO_FUNC_LOGE("over memory limit");
75         return NULL;
76     }
77     FfrtFunction* f = (FfrtFunction*)g_priv.ffrtAllocBase(FFRT_FUNCTION_KIND_GENERAL);
78     if (f == NULL) {
79         AUDIO_FUNC_LOGE("ffrt alloc fail");
80         return NULL;
81     }
82     f->header.exec = FfrtExecFunctionWrapper;
83     f->header.destroy = FfrtDestroyFunctionWrapper;
84     f->func = func;
85     f->afterFunc = afterFunc;
86     f->arg = arg;
87     return (FfrtFunctionHeader*)f;
88 }
89 
AudioPnpLoadFfrtLib(struct AudioPnpPriv * pPriv)90 static int32_t AudioPnpLoadFfrtLib(struct AudioPnpPriv *pPriv)
91 {
92     char *error = NULL;
93 #ifdef AUDIO_FEATURE_COMMUNITY
94     const char *ffrtLibPath = "/system/lib/chipset-sdk/libffrt.so";
95 #else
96     const char *ffrtLibPath = "/system/lib64/chipset-sdk/libffrt.so";
97 #endif
98     pPriv->handle = dlopen(ffrtLibPath, RTLD_LAZY);
99     if (pPriv->handle == NULL) {
100         error = dlerror();
101         AUDIO_FUNC_LOGE("audio pnp load path%{public}s, dlopen err=%{public}s", ffrtLibPath, error);
102         return HDF_FAILURE;
103     }
104     (void)dlerror(); // clear existing error
105     pPriv->ffrtAllocBase = dlsym(pPriv->handle, "ffrt_alloc_auto_managed_function_storage_base");
106     pPriv->ffrtInitAttr = dlsym(pPriv->handle, "ffrt_task_attr_init");
107     pPriv->ffrtSetQosAttr = dlsym(pPriv->handle, "ffrt_task_attr_set_qos");
108     pPriv->ffrtSetNameAttr = dlsym(pPriv->handle, "ffrt_task_attr_set_name");
109     pPriv->ffrtSubmitBase = dlsym(pPriv->handle, "ffrt_submit_base");
110     if (pPriv->ffrtAllocBase == NULL || pPriv->ffrtInitAttr == NULL || pPriv->ffrtSetQosAttr == NULL
111         || pPriv->ffrtSetNameAttr == NULL || pPriv->ffrtSubmitBase == NULL) {
112         error = dlerror();
113         AUDIO_FUNC_LOGE("dlsym ffrt err=%{public}s", error);
114         dlclose(pPriv->handle);
115         pPriv->handle = NULL;
116         return HDF_FAILURE;
117     }
118     AUDIO_FUNC_LOGD("audio pnp load ffrt lib success");
119     return HDF_SUCCESS;
120 }
121 
FfrtAttrInitFunc(void)122 FfrtTaskAttrInit FfrtAttrInitFunc(void)
123 {
124     return g_priv.ffrtInitAttr;
125 }
FfrtAttrSetQosFunc(void)126 FfrtTaskAttrSetQos FfrtAttrSetQosFunc(void)
127 {
128     return g_priv.ffrtSetQosAttr;
129 }
FfrtAttrSetNameFunc(void)130 FfrtTaskAttrSetName FfrtAttrSetNameFunc(void)
131 {
132     return g_priv.ffrtSetNameAttr;
133 }
FfrtSubmitBaseFunc(void)134 FfrtSubmitBase FfrtSubmitBaseFunc(void)
135 {
136     return g_priv.ffrtSubmitBase;
137 }
138 
139 static struct HdfDeviceObject *g_audioPnpDevice = NULL;
140 
AudioPnpUpdateInfo(const char * statusInfo)141 int32_t AudioPnpUpdateInfo(const char *statusInfo)
142 {
143     if (g_audioPnpDevice == NULL) {
144         AUDIO_FUNC_LOGE("g_audioPnpDevice is null!");
145         return HDF_ERR_INVALID_PARAM;
146     }
147     if (statusInfo == NULL) {
148         AUDIO_FUNC_LOGE("statusInfo is null!");
149         return HDF_ERR_INVALID_PARAM;
150     }
151 
152     if (HdfDeviceObjectSetServInfo(g_audioPnpDevice, statusInfo) != HDF_SUCCESS) {
153         AUDIO_FUNC_LOGE("set audio new status info failed!");
154         return HDF_FAILURE;
155     }
156     if (HdfDeviceObjectUpdate(g_audioPnpDevice) != HDF_SUCCESS) {
157         AUDIO_FUNC_LOGE("update audio status info failed!");
158         return HDF_FAILURE;
159     }
160 
161     return HDF_SUCCESS;
162 }
163 
AudioPnpUpdateInfoOnly(struct AudioEvent audioEvent)164 int32_t AudioPnpUpdateInfoOnly(struct AudioEvent audioEvent)
165 {
166     int32_t ret;
167     char pnpInfo[AUDIO_PNP_INFO_LEN_MAX] = {0};
168 
169     ret = snprintf_s(pnpInfo, AUDIO_PNP_INFO_LEN_MAX, AUDIO_PNP_INFO_LEN_MAX - 1, "EVENT_TYPE=%u;DEVICE_TYPE=%u",
170         audioEvent.eventType, audioEvent.deviceType);
171     if (ret < 0) {
172         AUDIO_FUNC_LOGE("snprintf_s failed!");
173         return HDF_FAILURE;
174     }
175 
176     ret = AudioPnpUpdateInfo(pnpInfo);
177     if (ret != HDF_SUCCESS) {
178         AUDIO_FUNC_LOGE("Update info failed: ret = %{public}d", ret);
179         return HDF_FAILURE;
180     }
181     AUDIO_FUNC_LOGD("Audio uevent:%{public}s", pnpInfo);
182 
183     return HDF_SUCCESS;
184 }
185 
HdfAudioPnpBind(struct HdfDeviceObject * device)186 static int32_t HdfAudioPnpBind(struct HdfDeviceObject *device)
187 {
188     AUDIO_FUNC_LOGI("enter.");
189     if (device == NULL) {
190         AUDIO_FUNC_LOGE("device is null!");
191         return HDF_ERR_INVALID_PARAM;
192     }
193     AUDIO_FUNC_LOGI("end.");
194 
195     return HDF_SUCCESS;
196 }
197 
HdfAudioPnpInit(struct HdfDeviceObject * device)198 static int32_t HdfAudioPnpInit(struct HdfDeviceObject *device)
199 {
200     AUDIO_FUNC_LOGI("enter.");
201     if (device == NULL) {
202         AUDIO_FUNC_LOGE("device is null!");
203         return HDF_ERR_INVALID_PARAM;
204     }
205 
206     if (!HdfDeviceSetClass(device, DEVICE_CLASS_AUDIO)) {
207         AUDIO_FUNC_LOGE("set audio class failed!");
208         return HDF_FAILURE;
209     }
210 
211     g_audioPnpDevice = device;
212 
213     if (AudioPnpLoadFfrtLib(&g_priv) < 0) {
214         AUDIO_FUNC_LOGE("audio pnp load ffrt lib fail");
215         return HDF_FAILURE;
216     }
217 
218     AudioUsbPnpUeventStartThread();
219     AudioHeadsetPnpInputStartThread();
220     AudioHdmiPnpUeventStartThread();
221     DetectAudioDevice(device);
222     AUDIO_FUNC_LOGI("end.");
223     return HDF_SUCCESS;
224 }
225 
HdfAudioPnpRelease(struct HdfDeviceObject * device)226 static void HdfAudioPnpRelease(struct HdfDeviceObject *device)
227 {
228     AUDIO_FUNC_LOGI("enter.");
229     if (device == NULL) {
230         AUDIO_FUNC_LOGE("device is null!");
231         return;
232     }
233 
234     AudioUsbPnpUeventStopThread();
235     AudioHeadsetPnpInputEndThread();
236     AudioHdmiPnpUeventStopThread();
237     device->service = NULL;
238 
239     AUDIO_FUNC_LOGI("end.");
240     return;
241 }
242 
AudioUhdfUnloadDriver(const char * driverName)243 int32_t AudioUhdfUnloadDriver(const char *driverName)
244 {
245     struct HdfSBuf *sBuf = NULL;
246     struct HdfIoService *service = NULL;
247 
248     if (driverName == NULL) {
249         AUDIO_FUNC_LOGE("param is NULL!");
250         return HDF_ERR_INVALID_PARAM;
251     }
252 
253     service = HdfIoServiceBind(AUDIO_CONTROL);
254     if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) {
255         AUDIO_FUNC_LOGE("Bind service failed!");
256         return HDF_FAILURE;
257     }
258 
259     sBuf = HdfSbufObtainDefaultSize();
260     if (sBuf == NULL) {
261         HdfIoServiceRecycle(service);
262         AUDIO_FUNC_LOGE("sbuf data malloc failed!");
263         return HDF_FAILURE;
264     }
265 
266     if (!HdfSbufWriteString(sBuf, driverName)) {
267         HdfSbufRecycle(sBuf);
268         HdfIoServiceRecycle(service);
269         AUDIO_FUNC_LOGE("driverName Write Fail!");
270         return HDF_FAILURE;
271     }
272 
273     int32_t ret = service->dispatcher->Dispatch(&service->object, AUDIODRV_CTRL_IOCTRL_ELEM_HDMI, sBuf, NULL);
274     if (ret != HDF_SUCCESS) {
275         HdfSbufRecycle(sBuf);
276         HdfIoServiceRecycle(service);
277         AUDIO_FUNC_LOGE("Unload HDMI Driver dispatch error");
278         return HDF_FAILURE;
279     }
280 
281     HdfSbufRecycle(sBuf);
282     HdfIoServiceRecycle(service);
283     return HDF_SUCCESS;
284 }
285 
AudioUhdfLoadDriver(const char * driverName)286 int32_t AudioUhdfLoadDriver(const char *driverName)
287 {
288     struct HdfIoService *serv = NULL;
289 
290     if (driverName == NULL) {
291         AUDIO_FUNC_LOGE("param is NULL!");
292         return HDF_ERR_INVALID_PARAM;
293     }
294 
295     serv = HdfIoServiceBind(driverName);
296     if (serv == NULL) {
297         AUDIO_FUNC_LOGE("error HdfIoServiceBind %{public}s", driverName);
298         return HDF_FAILURE;
299     }
300 
301     HdfIoServiceRecycle(serv);
302     return HDF_SUCCESS;
303 }
304 
305 struct HdfDriverEntry g_hdiAudioPnpEntry = {
306     .moduleVersion = 1,
307     .moduleName = "hdi_audio_pnp_server",
308     .Bind = HdfAudioPnpBind,
309     .Init = HdfAudioPnpInit,
310     .Release = HdfAudioPnpRelease,
311 };
312 
313 HDF_INIT(g_hdiAudioPnpEntry);
314