1/*
2 * Copyright (c) 2021 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 "usb_pnp_manager.h"
17#include <pthread.h>
18#include <unistd.h>
19
20#include "ddk_device_manager.h"
21#include "ddk_pnp_listener_mgr.h"
22#include "ddk_uevent_handle.h"
23#include "device_resource_if.h"
24#include "hdf_base.h"
25#include "hdf_device_desc.h"
26#include "hdf_device_object.h"
27#include "hdf_io_service_if.h"
28#include "hdf_log.h"
29#include "osal_mem.h"
30#include "securec.h"
31#include "usb_ddk_pnp_loader.h"
32#include "usbd_wrapper.h"
33
34#define HDF_LOG_TAG    usb_pnp_manager
35#define MODULENAMESIZE 128
36
37#ifdef USB_EMULATOR_MODE
38#define USB_GADGET_STATE_PATH "gadget_state_path"
39#define USB_GADGET_UEVENT_PATH "gadget_uevent_path"
40const char USB_EMULATOR_DEFAULT_STATE_PATH[] =  "/sys/class/gadget_usb/gadget0/state";
41const char USB_EMULATOR_DEFAULT_UEVENT_PATH[] = "/devices/virtual/gadget_usb/gadget0";
42#endif
43
44bool UsbPnpManagerWriteModuleName(struct HdfSBuf *sbuf, const char *moduleName)
45{
46    char modName[MODULENAMESIZE] = {0};
47    if (sprintf_s(modName, MODULENAMESIZE, "lib%s.z.so", moduleName) < 0) {
48        HDF_LOGE("%{public}s: sprintf_s modName failed", __func__);
49        return false;
50    }
51
52    return HdfSbufWriteString(sbuf, modName);
53}
54
55static int32_t UsbPnpManagerDispatch(
56    struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
57{
58    (void)client;
59    (void)cmd;
60    (void)data;
61    (void)reply;
62
63    HDF_LOGI("received cmd = %{public}d", cmd);
64    return HDF_SUCCESS;
65}
66
67static int32_t UsbPnpManagerBind(struct HdfDeviceObject *device)
68{
69    static struct IDeviceIoService pnpLoaderService = {
70        .Dispatch = UsbPnpManagerDispatch,
71    };
72
73    if (device == NULL) {
74        return HDF_ERR_INVALID_OBJECT;
75    }
76
77    device->service = &pnpLoaderService;
78    HDF_LOGI("usb pnp manager bind success");
79
80    return HDF_SUCCESS;
81}
82
83#ifdef USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
84int32_t UsbPnpManagerStartUeventThread(void)
85{
86    pthread_t tid;
87    int32_t ret = pthread_create(&tid, NULL, DdkUeventMain, NULL);
88    if (ret != 0) {
89        HDF_LOGE("%{public}s: create thread failed:%{public}d", __func__, ret);
90        return ret;
91    }
92
93    ret = pthread_setname_np(tid, "usbpnpUeventThd");
94    if (ret != 0) {
95        HDF_LOGE("%{public}s: set thread name failed:%{public}d", __func__, ret);
96    }
97    return ret;
98}
99#endif
100
101static const char *UsbPnpMgrGetGadgetPath(struct HdfDeviceObject *device, const char *attrName)
102{
103    struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
104    if (iface == NULL) {
105        HDF_LOGE("%{public}s: DeviceResourceGetIfaceInstance failed", __func__);
106        return NULL;
107    }
108
109    const char *path = NULL;
110    const char *pathDef = NULL;
111    if (device == NULL) {
112        HDF_LOGE("%{public}s: device is empty", __func__);
113        return NULL;
114    }
115#ifdef USB_EMULATOR_MODE
116    if (iface->GetString(device->property, attrName, &path, pathDef) != HDF_SUCCESS) {
117        HDF_LOGW("%{public}s: emulator read %{public}s failed", __func__, attrName);
118
119        if (strncmp(attrName, USB_GADGET_STATE_PATH, strlen(USB_GADGET_STATE_PATH)) == 0) {
120            path = USB_EMULATOR_DEFAULT_STATE_PATH;
121        } else {
122            path = USB_EMULATOR_DEFAULT_UEVENT_PATH;
123        }
124    }
125#else
126    if (iface->GetString(device->property, attrName, &path, pathDef) != HDF_SUCCESS) {
127        HDF_LOGE("%{public}s: read %{public}s failed", __func__, attrName);
128        return NULL;
129    }
130#endif
131    return path;
132}
133
134static int32_t UsbPnpManagerInit(struct HdfDeviceObject *device)
135{
136    static struct HdfDevEventlistener usbPnpListener = {
137        .callBack = UsbDdkPnpLoaderEventReceived,
138    };
139    usbPnpListener.priv = (void *)(device);
140
141    int32_t ret = DdkDevMgrInit(UsbPnpMgrGetGadgetPath(device, "gadget_state_path"));
142    if (ret != HDF_SUCCESS) {
143        HDF_LOGE("%{public}s: DdkDevMgrInit error", __func__);
144        return HDF_FAILURE;
145    }
146
147    ret = DdkListenerMgrInit();
148    if (ret != HDF_SUCCESS) {
149        HDF_LOGE("%{public}s: DdkListenerMgrInit error", __func__);
150        return HDF_FAILURE;
151    }
152
153    ret = DdkUeventInit(UsbPnpMgrGetGadgetPath(device, "gadget_uevent_path"));
154    if (ret != HDF_SUCCESS) {
155        HDF_LOGE("%{public}s: DdkUeventInit error", __func__);
156        return ret;
157    }
158#ifdef USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
159    if (UsbPnpManagerStartUeventThread() != HDF_SUCCESS) {
160        HDF_LOGE("%{public}s: start uevent thread failed", __func__);
161        return HDF_FAILURE;
162    }
163#endif
164
165#ifdef USB_EMULATOR_MODE
166    ret = UsbDdkPnpLoaderEventHandle();
167    if (ret != HDF_SUCCESS) {
168        HDF_LOGW("%{public}s: emulator, UsbDdkPnpLoaderEventHandle failed", __func__);
169    }
170    if (DdkListenerMgrAdd(&usbPnpListener) != HDF_SUCCESS) {
171        HDF_LOGW("%{public}s: emulator, add listener failed", __func__);
172    }
173#else
174    ret = UsbDdkPnpLoaderEventHandle();
175    if (ret != HDF_SUCCESS) {
176        HDF_LOGE("%{public}s: UsbDdkPnpLoaderEventHandle failed", __func__);
177        return ret;
178    }
179    if (DdkListenerMgrAdd(&usbPnpListener) != HDF_SUCCESS) {
180        HDF_LOGE("%{public}s: add listener failed", __func__);
181        return HDF_FAILURE;
182    }
183#endif
184    HDF_LOGI("UsbPnpManagerInit done");
185    return HDF_SUCCESS;
186}
187
188static void UsbPnpManagerRelease(struct HdfDeviceObject *device)
189{
190    (void)device;
191    return;
192}
193
194struct HdfDriverEntry g_usbPnpManagerEntry = {
195    .moduleVersion = 1,
196    .Bind = UsbPnpManagerBind,
197    .Init = UsbPnpManagerInit,
198    .Release = UsbPnpManagerRelease,
199    .moduleName = "HDF_USB_PNP_MANAGER",
200};
201
202HDF_INIT(g_usbPnpManagerEntry);
203