1cc290419Sopenharmony_ci/*
2cc290419Sopenharmony_ci * Copyright (C) 2024 Huawei Device Co., Ltd.
3cc290419Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4cc290419Sopenharmony_ci * you may not use this file except in compliance with the License.
5cc290419Sopenharmony_ci * You may obtain a copy of the License at
6cc290419Sopenharmony_ci *
7cc290419Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8cc290419Sopenharmony_ci *
9cc290419Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10cc290419Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11cc290419Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cc290419Sopenharmony_ci * See the License for the specific language governing permissions and
13cc290419Sopenharmony_ci * limitations under the License.
14cc290419Sopenharmony_ci */
15cc290419Sopenharmony_ci#include "host_usb.h"
16cc290419Sopenharmony_ci
17cc290419Sopenharmony_ci#include <thread>
18cc290419Sopenharmony_ci#include "usb_util.h"
19cc290419Sopenharmony_ci
20cc290419Sopenharmony_cinamespace Hdc {
21cc290419Sopenharmony_ciconstexpr uint16_t DEVICE_CHECK_INTERVAL = 3000;  // ms
22cc290419Sopenharmony_ciconstexpr uint16_t BUF_SIZE_MEDIUM = 512;
23cc290419Sopenharmony_ciconstexpr uint16_t BUF_SIZE_TINY = 64;
24cc290419Sopenharmony_ciconstexpr uint8_t GLOBAL_TIMEOUT = 30;
25cc290419Sopenharmony_ciconstexpr uint16_t TIME_BASE = 1000;
26cc290419Sopenharmony_ciconstexpr uint16_t MAX_SIZE_IOBUF = 61440;
27cc290419Sopenharmony_ci
28cc290419Sopenharmony_ciuint8_t *g_bufPtr = nullptr;
29cc290419Sopenharmony_ci
30cc290419Sopenharmony_ciconst std::string StringFormat(const char * const formater, va_list &vaArgs)
31cc290419Sopenharmony_ci{
32cc290419Sopenharmony_ci    std::vector<char> args(MAX_SIZE_IOBUF);
33cc290419Sopenharmony_ci    const int retSize = vsnprintf_s(args.data(), MAX_SIZE_IOBUF, MAX_SIZE_IOBUF - 1, formater, vaArgs);
34cc290419Sopenharmony_ci    if (retSize < 0) {
35cc290419Sopenharmony_ci        return std::string("");
36cc290419Sopenharmony_ci    } else {
37cc290419Sopenharmony_ci        return std::string(args.data(), retSize);
38cc290419Sopenharmony_ci    }
39cc290419Sopenharmony_ci}
40cc290419Sopenharmony_ci
41cc290419Sopenharmony_ciconst std::string StringFormat(const char * const formater, ...)
42cc290419Sopenharmony_ci{
43cc290419Sopenharmony_ci    va_list vaArgs;
44cc290419Sopenharmony_ci    va_start(vaArgs, formater);
45cc290419Sopenharmony_ci    std::string ret = StringFormat(formater, vaArgs);
46cc290419Sopenharmony_ci    va_end(vaArgs);
47cc290419Sopenharmony_ci    return ret;
48cc290419Sopenharmony_ci}
49cc290419Sopenharmony_ci
50cc290419Sopenharmony_ciHostUsb::HostUsb()
51cc290419Sopenharmony_ci{
52cc290419Sopenharmony_ci    if (libusb_init((libusb_context **)&ctxUSB) != 0) {
53cc290419Sopenharmony_ci        ctxUSB = nullptr;
54cc290419Sopenharmony_ci    }
55cc290419Sopenharmony_ci    running = false;
56cc290419Sopenharmony_ci}
57cc290419Sopenharmony_ci
58cc290419Sopenharmony_ciHostUsb::~HostUsb()
59cc290419Sopenharmony_ci{
60cc290419Sopenharmony_ci    if (running) {
61cc290419Sopenharmony_ci        Stop();
62cc290419Sopenharmony_ci    }
63cc290419Sopenharmony_ci}
64cc290419Sopenharmony_ci
65cc290419Sopenharmony_civoid HostUsb::Stop()
66cc290419Sopenharmony_ci{
67cc290419Sopenharmony_ci    if (!ctxUSB) {
68cc290419Sopenharmony_ci        return;
69cc290419Sopenharmony_ci    }
70cc290419Sopenharmony_ci    timer->Stop();
71cc290419Sopenharmony_ci    libusb_exit((libusb_context *)ctxUSB);
72cc290419Sopenharmony_ci    running = false;
73cc290419Sopenharmony_ci
74cc290419Sopenharmony_ci    if (g_bufPtr != nullptr) {
75cc290419Sopenharmony_ci        delete[] g_bufPtr;
76cc290419Sopenharmony_ci        g_bufPtr = nullptr;
77cc290419Sopenharmony_ci    }
78cc290419Sopenharmony_ci}
79cc290419Sopenharmony_ci
80cc290419Sopenharmony_ci// Main thread USB operates in this thread
81cc290419Sopenharmony_civoid HostUsb::UsbWorkThread(void *arg)
82cc290419Sopenharmony_ci{
83cc290419Sopenharmony_ci    HostUsb *thisClass = (HostUsb *)arg;
84cc290419Sopenharmony_ci    constexpr uint8_t usbHandleTimeout = 30;  // second
85cc290419Sopenharmony_ci    while (thisClass->running) {
86cc290419Sopenharmony_ci        struct timeval zerotime;
87cc290419Sopenharmony_ci        zerotime.tv_sec = usbHandleTimeout;
88cc290419Sopenharmony_ci        zerotime.tv_usec = 0;  // if == 0,windows will be high CPU load
89cc290419Sopenharmony_ci        libusb_handle_events_timeout(thisClass->ctxUSB, &zerotime);
90cc290419Sopenharmony_ci    }
91cc290419Sopenharmony_ci}
92cc290419Sopenharmony_ci
93cc290419Sopenharmony_civoid HostUsb::WatchUsbNodeChange(void *arg)
94cc290419Sopenharmony_ci{
95cc290419Sopenharmony_ci    HostUsb *thisClass = (HostUsb *)arg;
96cc290419Sopenharmony_ci    libusb_device **devs = nullptr;
97cc290419Sopenharmony_ci    libusb_device *dev = nullptr;
98cc290419Sopenharmony_ci    ssize_t cnt = libusb_get_device_list(thisClass->ctxUSB, &devs);
99cc290419Sopenharmony_ci    if (cnt < 0) {
100cc290419Sopenharmony_ci        return;
101cc290419Sopenharmony_ci    }
102cc290419Sopenharmony_ci    int i = 0;
103cc290419Sopenharmony_ci    // linux replug devid increment,windows will be not
104cc290419Sopenharmony_ci    while ((dev = devs[i++]) != nullptr) {  // must postfix++
105cc290419Sopenharmony_ci        std::string szTmpKey = StringFormat("%d-%d", libusb_get_bus_number(dev), libusb_get_device_address(dev));
106cc290419Sopenharmony_ci        // check is in ignore list
107cc290419Sopenharmony_ci        UsbCheckStatus statusCheck = thisClass->mapIgnoreDevice[szTmpKey];
108cc290419Sopenharmony_ci        if (statusCheck == HOST_USB_IGNORE || statusCheck == HOST_USB_REGISTER) {
109cc290419Sopenharmony_ci            continue;
110cc290419Sopenharmony_ci        }
111cc290419Sopenharmony_ci        std::string sn = szTmpKey;
112cc290419Sopenharmony_ci        if (thisClass->HasValidDevice(dev) && !thisClass->DetectMyNeed(dev, sn)) {
113cc290419Sopenharmony_ci            thisClass->ReviewUsbNodeLater(szTmpKey);
114cc290419Sopenharmony_ci        }
115cc290419Sopenharmony_ci    }
116cc290419Sopenharmony_ci    libusb_free_device_list(devs, 1);
117cc290419Sopenharmony_ci}
118cc290419Sopenharmony_ci
119cc290419Sopenharmony_civoid HostUsb::ReviewUsbNodeLater(string &nodeKey)
120cc290419Sopenharmony_ci{
121cc290419Sopenharmony_ci    // add to ignore list
122cc290419Sopenharmony_ci    mapIgnoreDevice[nodeKey] = HOST_USB_IGNORE;
123cc290419Sopenharmony_ci    RemoveIgnoreDevice(nodeKey);
124cc290419Sopenharmony_ci}
125cc290419Sopenharmony_ci
126cc290419Sopenharmony_cibool HostUsb::HasValidDevice(libusb_device *device)
127cc290419Sopenharmony_ci{
128cc290419Sopenharmony_ci    struct libusb_config_descriptor *descConfig = nullptr;
129cc290419Sopenharmony_ci    int ret = libusb_get_active_config_descriptor(device, &descConfig);
130cc290419Sopenharmony_ci    if (ret != 0) {
131cc290419Sopenharmony_ci        return false;
132cc290419Sopenharmony_ci    }
133cc290419Sopenharmony_ci    bool hasValid = false;
134cc290419Sopenharmony_ci    for (unsigned int j = 0; j < descConfig->bNumInterfaces; ++j) {
135cc290419Sopenharmony_ci        const struct libusb_interface *interface = &descConfig->interface[j];
136cc290419Sopenharmony_ci        if (interface->num_altsetting < 1) {
137cc290419Sopenharmony_ci            continue;
138cc290419Sopenharmony_ci        }
139cc290419Sopenharmony_ci        const struct libusb_interface_descriptor *ifDescriptor = &interface->altsetting[0];
140cc290419Sopenharmony_ci        if (!IsDebuggableDev(ifDescriptor)) {
141cc290419Sopenharmony_ci            continue;
142cc290419Sopenharmony_ci        }
143cc290419Sopenharmony_ci        hasValid = true;
144cc290419Sopenharmony_ci        break;
145cc290419Sopenharmony_ci    }
146cc290419Sopenharmony_ci    return hasValid;
147cc290419Sopenharmony_ci}
148cc290419Sopenharmony_ci
149cc290419Sopenharmony_cibool HostUsb::IsDebuggableDev(const struct libusb_interface_descriptor *ifDescriptor)
150cc290419Sopenharmony_ci{
151cc290419Sopenharmony_ci    constexpr uint8_t harmonyEpNum = 2;
152cc290419Sopenharmony_ci    constexpr uint8_t harmonyClass = 0xff;
153cc290419Sopenharmony_ci    constexpr uint8_t harmonySubClass = 0x50;
154cc290419Sopenharmony_ci    constexpr uint8_t harmonyProtocol = 0x01;
155cc290419Sopenharmony_ci
156cc290419Sopenharmony_ci    if (ifDescriptor->bInterfaceClass != harmonyClass || ifDescriptor->bInterfaceSubClass != harmonySubClass ||
157cc290419Sopenharmony_ci        ifDescriptor->bInterfaceProtocol != harmonyProtocol) {
158cc290419Sopenharmony_ci        return false;
159cc290419Sopenharmony_ci    }
160cc290419Sopenharmony_ci    if (ifDescriptor->bNumEndpoints != harmonyEpNum) {
161cc290419Sopenharmony_ci        return false;
162cc290419Sopenharmony_ci    }
163cc290419Sopenharmony_ci    return true;
164cc290419Sopenharmony_ci}
165cc290419Sopenharmony_ci
166cc290419Sopenharmony_cibool HostUsb::DetectMyNeed(libusb_device *device, string &sn)
167cc290419Sopenharmony_ci{
168cc290419Sopenharmony_ci    HUSB hUSB = new(std::nothrow) HdcUSB();
169cc290419Sopenharmony_ci    if (hUSB == nullptr) {
170cc290419Sopenharmony_ci        return false;
171cc290419Sopenharmony_ci    }
172cc290419Sopenharmony_ci    hUSB->device = device;
173cc290419Sopenharmony_ci    // just get usb SN, close handle immediately
174cc290419Sopenharmony_ci    int childRet = OpenDeviceMyNeed(hUSB);
175cc290419Sopenharmony_ci    if (childRet < 0) {
176cc290419Sopenharmony_ci        delete hUSB;
177cc290419Sopenharmony_ci        return false;
178cc290419Sopenharmony_ci    }
179cc290419Sopenharmony_ci    UpdateUSBDaemonInfo(hUSB, STATUS_READY);
180cc290419Sopenharmony_ci    mapIgnoreDevice[sn] = HOST_USB_REGISTER;
181cc290419Sopenharmony_ci    mapUsbDevice[hUSB->serialNumber] = hUSB;
182cc290419Sopenharmony_ci    return true;
183cc290419Sopenharmony_ci}
184cc290419Sopenharmony_ci
185cc290419Sopenharmony_civoid HostUsb::UpdateUSBDaemonInfo(HUSB hUSB, uint8_t connStatus)
186cc290419Sopenharmony_ci{
187cc290419Sopenharmony_ci    // add to list
188cc290419Sopenharmony_ci    HdcDaemonInformation di;
189cc290419Sopenharmony_ci    di.connectKey = hUSB->serialNumber;
190cc290419Sopenharmony_ci    di.connType = CONN_USB;
191cc290419Sopenharmony_ci    di.connStatus = connStatus;
192cc290419Sopenharmony_ci    di.usbMountPoint = "";
193cc290419Sopenharmony_ci    di.usbMountPoint = StringFormat("%d-%d", hUSB->busId, hUSB->devId);
194cc290419Sopenharmony_ci
195cc290419Sopenharmony_ci    HDaemonInfo pDi = nullptr;
196cc290419Sopenharmony_ci    HDaemonInfo hdiNew = &di;
197cc290419Sopenharmony_ci    AdminDaemonMap(OP_QUERY, hUSB->serialNumber, pDi);
198cc290419Sopenharmony_ci    if (!pDi) {
199cc290419Sopenharmony_ci        AdminDaemonMap(OP_ADD, hUSB->serialNumber, hdiNew);
200cc290419Sopenharmony_ci    } else {
201cc290419Sopenharmony_ci        AdminDaemonMap(OP_UPDATE, hUSB->serialNumber, hdiNew);
202cc290419Sopenharmony_ci        if (connStatus == STATUS_OFFLINE) {
203cc290419Sopenharmony_ci            RemoveIgnoreDevice(di.usbMountPoint);
204cc290419Sopenharmony_ci        }
205cc290419Sopenharmony_ci    }
206cc290419Sopenharmony_ci}
207cc290419Sopenharmony_ci
208cc290419Sopenharmony_ci// ==0 Represents new equipment and is what we need,<0  my need
209cc290419Sopenharmony_ciint HostUsb::OpenDeviceMyNeed(HUSB hUSB)
210cc290419Sopenharmony_ci{
211cc290419Sopenharmony_ci    libusb_device *device = hUSB->device;
212cc290419Sopenharmony_ci    int ret = -1;
213cc290419Sopenharmony_ci    int openRet = libusb_open(device, &hUSB->devHandle);
214cc290419Sopenharmony_ci    if (openRet != LIBUSB_SUCCESS) {
215cc290419Sopenharmony_ci        return -1;
216cc290419Sopenharmony_ci    }
217cc290419Sopenharmony_ci    while (running) {
218cc290419Sopenharmony_ci        libusb_device_handle *handle = hUSB->devHandle;
219cc290419Sopenharmony_ci        struct libusb_device_descriptor desc;
220cc290419Sopenharmony_ci        if (CheckDescriptor(hUSB, desc)) {
221cc290419Sopenharmony_ci            break;
222cc290419Sopenharmony_ci        }
223cc290419Sopenharmony_ci#ifdef HOST_MAC
224cc290419Sopenharmony_ci        if (CheckActiveConfig(device, hUSB, desc)) {
225cc290419Sopenharmony_ci#else
226cc290419Sopenharmony_ci        if (CheckActiveConfig(device, hUSB)) {
227cc290419Sopenharmony_ci#endif
228cc290419Sopenharmony_ci            break;
229cc290419Sopenharmony_ci        }
230cc290419Sopenharmony_ci
231cc290419Sopenharmony_ci        // USB filter rules are set according to specific device pedding device
232cc290419Sopenharmony_ci        ret = libusb_claim_interface(handle, hUSB->interfaceNumber);
233cc290419Sopenharmony_ci        break;
234cc290419Sopenharmony_ci    }
235cc290419Sopenharmony_ci    if (ret) {
236cc290419Sopenharmony_ci        // not my need device, release the device
237cc290419Sopenharmony_ci        libusb_close(hUSB->devHandle);
238cc290419Sopenharmony_ci        hUSB->devHandle = nullptr;
239cc290419Sopenharmony_ci    }
240cc290419Sopenharmony_ci    return ret;
241cc290419Sopenharmony_ci}
242cc290419Sopenharmony_ci
243cc290419Sopenharmony_ciint HostUsb::CheckDescriptor(HUSB hUSB, libusb_device_descriptor& desc)
244cc290419Sopenharmony_ci{
245cc290419Sopenharmony_ci    char serialNum[BUF_SIZE_MEDIUM] = "";
246cc290419Sopenharmony_ci    int childRet = 0;
247cc290419Sopenharmony_ci    uint8_t curBus = libusb_get_bus_number(hUSB->device);
248cc290419Sopenharmony_ci    uint8_t curDev = libusb_get_device_address(hUSB->device);
249cc290419Sopenharmony_ci    hUSB->busId = curBus;
250cc290419Sopenharmony_ci    hUSB->devId = curDev;
251cc290419Sopenharmony_ci    if (libusb_get_device_descriptor(hUSB->device, &desc)) {
252cc290419Sopenharmony_ci        return -1;
253cc290419Sopenharmony_ci    }
254cc290419Sopenharmony_ci    // Get the serial number of the device, if there is no serial number, use the ID number to replace
255cc290419Sopenharmony_ci    // If the device is not in time, occasionally can't get it, this is determined by the external factor, cannot be
256cc290419Sopenharmony_ci    // changed. LIBUSB_SUCCESS
257cc290419Sopenharmony_ci    childRet = libusb_get_string_descriptor_ascii(hUSB->devHandle, desc.iSerialNumber, (uint8_t *)serialNum,
258cc290419Sopenharmony_ci                                                  sizeof(serialNum));
259cc290419Sopenharmony_ci    if (childRet < 0) {
260cc290419Sopenharmony_ci        return -1;
261cc290419Sopenharmony_ci    } else {
262cc290419Sopenharmony_ci        hUSB->serialNumber = serialNum;
263cc290419Sopenharmony_ci    }
264cc290419Sopenharmony_ci    return 0;
265cc290419Sopenharmony_ci}
266cc290419Sopenharmony_ci
267cc290419Sopenharmony_ci#ifdef HOST_MAC
268cc290419Sopenharmony_ciint HostUsb::CheckActiveConfig(libusb_device *device, HUSB hUSB, libusb_device_descriptor& desc)
269cc290419Sopenharmony_ci#else
270cc290419Sopenharmony_ciint HostUsb::CheckActiveConfig(libusb_device *device, HUSB hUSB)
271cc290419Sopenharmony_ci#endif
272cc290419Sopenharmony_ci{
273cc290419Sopenharmony_ci    struct libusb_config_descriptor *descConfig = nullptr;
274cc290419Sopenharmony_ci    int ret = libusb_get_active_config_descriptor(device, &descConfig);
275cc290419Sopenharmony_ci    if (ret != 0) {
276cc290419Sopenharmony_ci#ifdef HOST_MAC
277cc290419Sopenharmony_ci        if ((desc.bDeviceClass == 0xFF)
278cc290419Sopenharmony_ci            && (desc.bDeviceSubClass == 0xFF)
279cc290419Sopenharmony_ci            && (desc.bDeviceProtocol == 0xFF)) {
280cc290419Sopenharmony_ci            ret = libusb_set_configuration(hUSB->devHandle, 1);
281cc290419Sopenharmony_ci            if (ret != 0) {
282cc290419Sopenharmony_ci                return -1;
283cc290419Sopenharmony_ci            }
284cc290419Sopenharmony_ci        }
285cc290419Sopenharmony_ci
286cc290419Sopenharmony_ci        ret = libusb_get_active_config_descriptor(device, &descConfig);
287cc290419Sopenharmony_ci        if (ret != 0) {
288cc290419Sopenharmony_ci#endif
289cc290419Sopenharmony_ci            return -1;
290cc290419Sopenharmony_ci        }
291cc290419Sopenharmony_ci#ifdef HOST_MAC
292cc290419Sopenharmony_ci    }
293cc290419Sopenharmony_ci#endif
294cc290419Sopenharmony_ci
295cc290419Sopenharmony_ci    ret = -1;
296cc290419Sopenharmony_ci    CheckUsbEndpoint(ret, hUSB, descConfig);
297cc290419Sopenharmony_ci    libusb_free_config_descriptor(descConfig);
298cc290419Sopenharmony_ci    return ret;
299cc290419Sopenharmony_ci}
300cc290419Sopenharmony_ci
301cc290419Sopenharmony_civoid HostUsb::CheckUsbEndpoint(int& ret, HUSB hUSB, libusb_config_descriptor *descConfig)
302cc290419Sopenharmony_ci{
303cc290419Sopenharmony_ci    unsigned int j = 0;
304cc290419Sopenharmony_ci    for (j = 0; j < descConfig->bNumInterfaces; ++j) {
305cc290419Sopenharmony_ci        const struct libusb_interface *interface = &descConfig->interface[j];
306cc290419Sopenharmony_ci        if (interface->num_altsetting < 1) {
307cc290419Sopenharmony_ci            continue;
308cc290419Sopenharmony_ci        }
309cc290419Sopenharmony_ci        const struct libusb_interface_descriptor *ifDescriptor = &interface->altsetting[0];
310cc290419Sopenharmony_ci        if (!IsDebuggableDev(ifDescriptor)) {
311cc290419Sopenharmony_ci            continue;
312cc290419Sopenharmony_ci        }
313cc290419Sopenharmony_ci        hUSB->interfaceNumber = ifDescriptor->bInterfaceNumber;
314cc290419Sopenharmony_ci        unsigned int k = 0;
315cc290419Sopenharmony_ci        for (k = 0; k < ifDescriptor->bNumEndpoints; ++k) {
316cc290419Sopenharmony_ci            const struct libusb_endpoint_descriptor *ep_desc = &ifDescriptor->endpoint[k];
317cc290419Sopenharmony_ci            if ((ep_desc->bmAttributes & 0x03) != LIBUSB_TRANSFER_TYPE_BULK) {
318cc290419Sopenharmony_ci                continue;
319cc290419Sopenharmony_ci            }
320cc290419Sopenharmony_ci            if (ep_desc->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
321cc290419Sopenharmony_ci                hUSB->hostBulkIn.endpoint = ep_desc->bEndpointAddress;
322cc290419Sopenharmony_ci                hUSB->hostBulkIn.bulkInOut = true;
323cc290419Sopenharmony_ci            } else {
324cc290419Sopenharmony_ci                hUSB->hostBulkOut.endpoint = ep_desc->bEndpointAddress;
325cc290419Sopenharmony_ci                hUSB->wMaxPacketSizeSend = ep_desc->wMaxPacketSize;
326cc290419Sopenharmony_ci                hUSB->hostBulkOut.bulkInOut = false;
327cc290419Sopenharmony_ci            }
328cc290419Sopenharmony_ci        }
329cc290419Sopenharmony_ci        if (hUSB->hostBulkIn.endpoint == 0 || hUSB->hostBulkOut.endpoint == 0) {
330cc290419Sopenharmony_ci            break;
331cc290419Sopenharmony_ci        }
332cc290419Sopenharmony_ci        ret = 0;
333cc290419Sopenharmony_ci    }
334cc290419Sopenharmony_ci}
335cc290419Sopenharmony_ci
336cc290419Sopenharmony_cibool HostUsb::FindDeviceByID(HUSB hUSB, const char *usbMountPoint, libusb_context *ctxUSB)
337cc290419Sopenharmony_ci{
338cc290419Sopenharmony_ci    libusb_device **listDevices = nullptr;
339cc290419Sopenharmony_ci    bool ret = false;
340cc290419Sopenharmony_ci    char tmpStr[BUF_SIZE_TINY] = "";
341cc290419Sopenharmony_ci    int busNum = 0;
342cc290419Sopenharmony_ci    int devNum = 0;
343cc290419Sopenharmony_ci    int curBus = 0;
344cc290419Sopenharmony_ci    int curDev = 0;
345cc290419Sopenharmony_ci
346cc290419Sopenharmony_ci    int deviceNum = libusb_get_device_list(ctxUSB, &listDevices);
347cc290419Sopenharmony_ci    if (deviceNum <= 0) {
348cc290419Sopenharmony_ci        libusb_free_device_list(listDevices, 1);
349cc290419Sopenharmony_ci        return false;
350cc290419Sopenharmony_ci    }
351cc290419Sopenharmony_ci    if (strchr(usbMountPoint, '-') && EOK == strcpy_s(tmpStr, sizeof(tmpStr), usbMountPoint)) {
352cc290419Sopenharmony_ci        *strchr(tmpStr, '-') = '\0';
353cc290419Sopenharmony_ci        busNum = atoi(tmpStr);
354cc290419Sopenharmony_ci        devNum = atoi(tmpStr + strlen(tmpStr) + 1);
355cc290419Sopenharmony_ci    } else {
356cc290419Sopenharmony_ci        return false;
357cc290419Sopenharmony_ci    }
358cc290419Sopenharmony_ci
359cc290419Sopenharmony_ci    int i = 0;
360cc290419Sopenharmony_ci    for (i = 0; i < deviceNum; ++i) {
361cc290419Sopenharmony_ci        struct libusb_device_descriptor desc;
362cc290419Sopenharmony_ci        if (LIBUSB_SUCCESS != libusb_get_device_descriptor(listDevices[i], &desc)) {
363cc290419Sopenharmony_ci            continue;
364cc290419Sopenharmony_ci        }
365cc290419Sopenharmony_ci        curBus = libusb_get_bus_number(listDevices[i]);
366cc290419Sopenharmony_ci        curDev = libusb_get_device_address(listDevices[i]);
367cc290419Sopenharmony_ci        if ((curBus == busNum && curDev == devNum)) {
368cc290419Sopenharmony_ci            hUSB->device = listDevices[i];
369cc290419Sopenharmony_ci            int childRet = OpenDeviceMyNeed(hUSB);
370cc290419Sopenharmony_ci            if (!childRet) {
371cc290419Sopenharmony_ci                ret = true;
372cc290419Sopenharmony_ci            } else {
373cc290419Sopenharmony_ci                string key = string(usbMountPoint);
374cc290419Sopenharmony_ci                RemoveIgnoreDevice(key);
375cc290419Sopenharmony_ci            }
376cc290419Sopenharmony_ci            break;
377cc290419Sopenharmony_ci        }
378cc290419Sopenharmony_ci    }
379cc290419Sopenharmony_ci    libusb_free_device_list(listDevices, 1);
380cc290419Sopenharmony_ci    return ret;
381cc290419Sopenharmony_ci}
382cc290419Sopenharmony_ci
383cc290419Sopenharmony_ci// multi-thread calll
384cc290419Sopenharmony_civoid HostUsb::CancelUsbIo(HUSB hUSB)
385cc290419Sopenharmony_ci{
386cc290419Sopenharmony_ci    std::unique_lock<std::mutex> lock(hUSB->lockDeviceHandle);
387cc290419Sopenharmony_ci    if (!hUSB->hostBulkIn.isShutdown) {
388cc290419Sopenharmony_ci        if (!hUSB->hostBulkIn.isComplete) {
389cc290419Sopenharmony_ci            libusb_cancel_transfer(hUSB->hostBulkIn.transfer);
390cc290419Sopenharmony_ci            hUSB->hostBulkIn.cv.notify_one();
391cc290419Sopenharmony_ci        } else {
392cc290419Sopenharmony_ci            hUSB->hostBulkIn.isShutdown = true;
393cc290419Sopenharmony_ci        }
394cc290419Sopenharmony_ci    }
395cc290419Sopenharmony_ci    if (!hUSB->hostBulkOut.isShutdown) {
396cc290419Sopenharmony_ci        if (!hUSB->hostBulkOut.isComplete) {
397cc290419Sopenharmony_ci            libusb_cancel_transfer(hUSB->hostBulkOut.transfer);
398cc290419Sopenharmony_ci            hUSB->hostBulkOut.cv.notify_one();
399cc290419Sopenharmony_ci        } else {
400cc290419Sopenharmony_ci            hUSB->hostBulkOut.isShutdown = true;
401cc290419Sopenharmony_ci        }
402cc290419Sopenharmony_ci    }
403cc290419Sopenharmony_ci}
404cc290419Sopenharmony_ci
405cc290419Sopenharmony_civoid HostUsb::RemoveIgnoreDevice(string &mountInfo)
406cc290419Sopenharmony_ci{
407cc290419Sopenharmony_ci    if (mapIgnoreDevice.count(mountInfo)) {
408cc290419Sopenharmony_ci        mapIgnoreDevice.erase(mountInfo);
409cc290419Sopenharmony_ci    }
410cc290419Sopenharmony_ci}
411cc290419Sopenharmony_ci
412cc290419Sopenharmony_civoid LIBUSB_CALL HostUsb::USBBulkCallback(struct libusb_transfer *transfer)
413cc290419Sopenharmony_ci{
414cc290419Sopenharmony_ci    auto *ep = reinterpret_cast<HostUSBEndpoint *>(transfer->user_data);
415cc290419Sopenharmony_ci    std::unique_lock<std::mutex> lock(ep->mutexIo);
416cc290419Sopenharmony_ci    bool retrySumit = false;
417cc290419Sopenharmony_ci    int childRet = 0;
418cc290419Sopenharmony_ci    do {
419cc290419Sopenharmony_ci        if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
420cc290419Sopenharmony_ci            break;
421cc290419Sopenharmony_ci        }
422cc290419Sopenharmony_ci        if (!ep->bulkInOut && transfer->actual_length != transfer->length) {
423cc290419Sopenharmony_ci            transfer->length -= transfer->actual_length;
424cc290419Sopenharmony_ci            transfer->buffer += transfer->actual_length;
425cc290419Sopenharmony_ci            retrySumit = true;
426cc290419Sopenharmony_ci            break;
427cc290419Sopenharmony_ci        }
428cc290419Sopenharmony_ci    } while (false);
429cc290419Sopenharmony_ci    while (retrySumit) {
430cc290419Sopenharmony_ci        childRet = libusb_submit_transfer(transfer);
431cc290419Sopenharmony_ci        if (childRet != 0) {
432cc290419Sopenharmony_ci            transfer->status = LIBUSB_TRANSFER_ERROR;
433cc290419Sopenharmony_ci            break;
434cc290419Sopenharmony_ci        }
435cc290419Sopenharmony_ci        return;
436cc290419Sopenharmony_ci    }
437cc290419Sopenharmony_ci    ep->isComplete = true;
438cc290419Sopenharmony_ci    ep->cv.notify_one();
439cc290419Sopenharmony_ci}
440cc290419Sopenharmony_ci
441cc290419Sopenharmony_ciPersistBuffer HostUsb::ReadUsbIO(HUSB hUSB, int exceptedSize)
442cc290419Sopenharmony_ci{
443cc290419Sopenharmony_ci    int timeout = 0;
444cc290419Sopenharmony_ci    int childRet = 0;
445cc290419Sopenharmony_ci    int ret = 0;
446cc290419Sopenharmony_ci
447cc290419Sopenharmony_ci    HostUSBEndpoint* ep = &hUSB->hostBulkIn;
448cc290419Sopenharmony_ci
449cc290419Sopenharmony_ci    if (g_bufPtr == nullptr) {
450cc290419Sopenharmony_ci        g_bufPtr = new uint8_t[MAX_SIZE_IOBUF];
451cc290419Sopenharmony_ci    }
452cc290419Sopenharmony_ci
453cc290419Sopenharmony_ci    hUSB->lockDeviceHandle.lock();
454cc290419Sopenharmony_ci    ep->isComplete = false;
455cc290419Sopenharmony_ci    do {
456cc290419Sopenharmony_ci        std::unique_lock<std::mutex> lock(ep->mutexIo);
457cc290419Sopenharmony_ci        libusb_fill_bulk_transfer(ep->transfer, hUSB->devHandle, ep->endpoint, g_bufPtr, exceptedSize,
458cc290419Sopenharmony_ci            USBBulkCallback, ep, timeout);
459cc290419Sopenharmony_ci        childRet = libusb_submit_transfer(ep->transfer);
460cc290419Sopenharmony_ci        hUSB->lockDeviceHandle.unlock();
461cc290419Sopenharmony_ci        if (childRet < 0) {
462cc290419Sopenharmony_ci            break;
463cc290419Sopenharmony_ci        }
464cc290419Sopenharmony_ci        ep->cv.wait(lock, [ep]() { return ep->isComplete; });
465cc290419Sopenharmony_ci        if (ep->transfer->status != 0) {
466cc290419Sopenharmony_ci            break;
467cc290419Sopenharmony_ci        }
468cc290419Sopenharmony_ci        ret = ep->transfer->actual_length;
469cc290419Sopenharmony_ci    } while (false);
470cc290419Sopenharmony_ci    return PersistBuffer{reinterpret_cast<char *>(g_bufPtr), static_cast<uint64_t>(ret)};
471cc290419Sopenharmony_ci}
472cc290419Sopenharmony_ci
473cc290419Sopenharmony_ciHUSB HostUsb::GetUsbDevice(std::string connectKey)
474cc290419Sopenharmony_ci{
475cc290419Sopenharmony_ci    return mapUsbDevice[connectKey];
476cc290419Sopenharmony_ci}
477cc290419Sopenharmony_ci
478cc290419Sopenharmony_ciint HostUsb::WriteUsbIO(HUSB hUSB, SerializedBuffer buf)
479cc290419Sopenharmony_ci{
480cc290419Sopenharmony_ci    int childRet = 0;
481cc290419Sopenharmony_ci    int ret = -14000;
482cc290419Sopenharmony_ci    int timeout = GLOBAL_TIMEOUT * TIME_BASE;
483cc290419Sopenharmony_ci    HostUSBEndpoint *ep = &hUSB->hostBulkOut;
484cc290419Sopenharmony_ci
485cc290419Sopenharmony_ci    hUSB->lockDeviceHandle.lock();
486cc290419Sopenharmony_ci    ep->isComplete = false;
487cc290419Sopenharmony_ci    uint8_t* ptr = reinterpret_cast<uint8_t *>(buf.ptr);
488cc290419Sopenharmony_ci    size_t size = static_cast<size_t>(buf.size);
489cc290419Sopenharmony_ci    do {
490cc290419Sopenharmony_ci        std::unique_lock<std::mutex> lock(ep->mutexIo);
491cc290419Sopenharmony_ci        libusb_fill_bulk_transfer(ep->transfer, hUSB->devHandle, ep->endpoint, ptr, size, USBBulkCallback, ep,
492cc290419Sopenharmony_ci                                  timeout);
493cc290419Sopenharmony_ci        childRet = libusb_submit_transfer(ep->transfer);
494cc290419Sopenharmony_ci        hUSB->lockDeviceHandle.unlock();
495cc290419Sopenharmony_ci        if (childRet < 0) {
496cc290419Sopenharmony_ci            break;
497cc290419Sopenharmony_ci        }
498cc290419Sopenharmony_ci        ep->cv.wait(lock, [ep]() { return ep->isComplete; });
499cc290419Sopenharmony_ci        if (ep->transfer->status != 0) {
500cc290419Sopenharmony_ci            break;
501cc290419Sopenharmony_ci        }
502cc290419Sopenharmony_ci        ret = ep->transfer->actual_length;
503cc290419Sopenharmony_ci    } while (false);
504cc290419Sopenharmony_ci    return ret;
505cc290419Sopenharmony_ci}
506cc290419Sopenharmony_ci
507cc290419Sopenharmony_ciint HostUsb::Initial()
508cc290419Sopenharmony_ci{
509cc290419Sopenharmony_ci    if (!ctxUSB) {
510cc290419Sopenharmony_ci        return -1;
511cc290419Sopenharmony_ci    }
512cc290419Sopenharmony_ci    running = true;
513cc290419Sopenharmony_ci    auto WatchUsbNodeChangeFunc = [this]() { WatchUsbNodeChange(this); };
514cc290419Sopenharmony_ci    timer = std::make_unique<CTimer>(WatchUsbNodeChangeFunc);
515cc290419Sopenharmony_ci    timer->Start(DEVICE_CHECK_INTERVAL);
516cc290419Sopenharmony_ci    std::thread([this]() {
517cc290419Sopenharmony_ci        UsbWorkThread(this);
518cc290419Sopenharmony_ci    }).detach();
519cc290419Sopenharmony_ci    return 0;
520cc290419Sopenharmony_ci}
521cc290419Sopenharmony_ci
522cc290419Sopenharmony_cistatic void BuildDaemonVisableLine(HDaemonInfo hdi, bool fullDisplay, string &out)
523cc290419Sopenharmony_ci{
524cc290419Sopenharmony_ci    if (fullDisplay) {
525cc290419Sopenharmony_ci        string sConn;
526cc290419Sopenharmony_ci        string sStatus;
527cc290419Sopenharmony_ci        switch (hdi->connType) {
528cc290419Sopenharmony_ci            case CONN_TCP:
529cc290419Sopenharmony_ci                sConn = "TCP";
530cc290419Sopenharmony_ci                break;
531cc290419Sopenharmony_ci            case CONN_USB:
532cc290419Sopenharmony_ci                sConn = "USB";
533cc290419Sopenharmony_ci                break;
534cc290419Sopenharmony_ci#ifdef HDC_SUPPORT_UART
535cc290419Sopenharmony_ci            case CONN_SERIAL:
536cc290419Sopenharmony_ci                sConn = "UART";
537cc290419Sopenharmony_ci                break;
538cc290419Sopenharmony_ci#endif
539cc290419Sopenharmony_ci            case CONN_BT:
540cc290419Sopenharmony_ci                sConn = "BT";
541cc290419Sopenharmony_ci                break;
542cc290419Sopenharmony_ci            default:
543cc290419Sopenharmony_ci                sConn = "UNKNOW";
544cc290419Sopenharmony_ci                break;
545cc290419Sopenharmony_ci        }
546cc290419Sopenharmony_ci        switch (hdi->connStatus) {
547cc290419Sopenharmony_ci            case STATUS_READY:
548cc290419Sopenharmony_ci                sStatus = "Ready";
549cc290419Sopenharmony_ci                break;
550cc290419Sopenharmony_ci            case STATUS_CONNECTED:
551cc290419Sopenharmony_ci                sStatus = "Connected";
552cc290419Sopenharmony_ci                break;
553cc290419Sopenharmony_ci            case STATUS_OFFLINE:
554cc290419Sopenharmony_ci                sStatus = "Offline";
555cc290419Sopenharmony_ci                break;
556cc290419Sopenharmony_ci            default:
557cc290419Sopenharmony_ci                sStatus = "UNKNOW";
558cc290419Sopenharmony_ci                break;
559cc290419Sopenharmony_ci        }
560cc290419Sopenharmony_ci        out = StringFormat("%s\t\t%s\t%s\t%s\n", hdi->connectKey.c_str(), sConn.c_str(), sStatus.c_str(),
561cc290419Sopenharmony_ci                  hdi->devName.c_str());
562cc290419Sopenharmony_ci    } else {
563cc290419Sopenharmony_ci        if (hdi->connStatus == STATUS_CONNECTED) {
564cc290419Sopenharmony_ci            out = StringFormat("%s\n", hdi->connectKey.c_str());
565cc290419Sopenharmony_ci        }
566cc290419Sopenharmony_ci    }
567cc290419Sopenharmony_ci}
568cc290419Sopenharmony_ci
569cc290419Sopenharmony_cistring HostUsb::GetDaemonMapList(uint8_t opType)
570cc290419Sopenharmony_ci{
571cc290419Sopenharmony_ci    string ret;
572cc290419Sopenharmony_ci    bool fullDisplay = false;
573cc290419Sopenharmony_ci    if (opType == OP_GET_STRLIST_FULL) {
574cc290419Sopenharmony_ci        fullDisplay = true;
575cc290419Sopenharmony_ci    }
576cc290419Sopenharmony_ci    lockMapDaemon.lock();
577cc290419Sopenharmony_ci    map<string, HDaemonInfo>::iterator iter;
578cc290419Sopenharmony_ci    string echoLine;
579cc290419Sopenharmony_ci    for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
580cc290419Sopenharmony_ci        HDaemonInfo di = iter->second;
581cc290419Sopenharmony_ci        if (!di) {
582cc290419Sopenharmony_ci            continue;
583cc290419Sopenharmony_ci        }
584cc290419Sopenharmony_ci        echoLine = "";
585cc290419Sopenharmony_ci        if (opType == OP_GET_READY_STRLIST) {
586cc290419Sopenharmony_ci            if (di->connStatus == STATUS_READY) {
587cc290419Sopenharmony_ci                echoLine = StringFormat("%s ", di->connectKey.c_str());
588cc290419Sopenharmony_ci                ret += echoLine;
589cc290419Sopenharmony_ci            }
590cc290419Sopenharmony_ci            continue;
591cc290419Sopenharmony_ci        }
592cc290419Sopenharmony_ci        BuildDaemonVisableLine(di, fullDisplay, echoLine);
593cc290419Sopenharmony_ci        ret += echoLine;
594cc290419Sopenharmony_ci    }
595cc290419Sopenharmony_ci    lockMapDaemon.unlock();
596cc290419Sopenharmony_ci    return ret;
597cc290419Sopenharmony_ci}
598cc290419Sopenharmony_ci
599cc290419Sopenharmony_cistring HostUsb::AdminDaemonMap(uint8_t opType, const string &connectKey, HDaemonInfo &hDaemonInfoInOut)
600cc290419Sopenharmony_ci{
601cc290419Sopenharmony_ci    string sRet;
602cc290419Sopenharmony_ci    switch (opType) {
603cc290419Sopenharmony_ci        case OP_ADD: {
604cc290419Sopenharmony_ci            HDaemonInfo pdiNew = new(std::nothrow) HdcDaemonInformation();
605cc290419Sopenharmony_ci            if (pdiNew == nullptr) {
606cc290419Sopenharmony_ci                break;
607cc290419Sopenharmony_ci            }
608cc290419Sopenharmony_ci            *pdiNew = *hDaemonInfoInOut;
609cc290419Sopenharmony_ci            lockMapDaemon.lock();
610cc290419Sopenharmony_ci            if (!mapDaemon[hDaemonInfoInOut->connectKey]) {
611cc290419Sopenharmony_ci                mapDaemon[hDaemonInfoInOut->connectKey] = pdiNew;
612cc290419Sopenharmony_ci            }
613cc290419Sopenharmony_ci            lockMapDaemon.unlock();
614cc290419Sopenharmony_ci            break;
615cc290419Sopenharmony_ci        }
616cc290419Sopenharmony_ci        case OP_GET_READY_STRLIST:
617cc290419Sopenharmony_ci            sRet = GetDaemonMapList(opType);
618cc290419Sopenharmony_ci            break;
619cc290419Sopenharmony_ci        case OP_GET_STRLIST:
620cc290419Sopenharmony_ci        case OP_GET_STRLIST_FULL: {
621cc290419Sopenharmony_ci            sRet = GetDaemonMapList(opType);
622cc290419Sopenharmony_ci            break;
623cc290419Sopenharmony_ci        }
624cc290419Sopenharmony_ci        case OP_QUERY: {
625cc290419Sopenharmony_ci            lockMapDaemon.lock();
626cc290419Sopenharmony_ci            if (mapDaemon.count(connectKey)) {
627cc290419Sopenharmony_ci                hDaemonInfoInOut = mapDaemon[connectKey];
628cc290419Sopenharmony_ci            }
629cc290419Sopenharmony_ci            lockMapDaemon.unlock();
630cc290419Sopenharmony_ci            break;
631cc290419Sopenharmony_ci        }
632cc290419Sopenharmony_ci        case OP_REMOVE: {
633cc290419Sopenharmony_ci            lockMapDaemon.lock();
634cc290419Sopenharmony_ci            if (mapDaemon.count(connectKey)) {
635cc290419Sopenharmony_ci                mapDaemon.erase(connectKey);
636cc290419Sopenharmony_ci            }
637cc290419Sopenharmony_ci            lockMapDaemon.unlock();
638cc290419Sopenharmony_ci            break;
639cc290419Sopenharmony_ci        }
640cc290419Sopenharmony_ci        case OP_GET_ANY: {
641cc290419Sopenharmony_ci            lockMapDaemon.lock();
642cc290419Sopenharmony_ci            map<string, HDaemonInfo>::iterator iter;
643cc290419Sopenharmony_ci            for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
644cc290419Sopenharmony_ci                HDaemonInfo di = iter->second;
645cc290419Sopenharmony_ci                // usb will be auto connected
646cc290419Sopenharmony_ci                if (di->connStatus == STATUS_READY || di->connStatus == STATUS_CONNECTED) {
647cc290419Sopenharmony_ci                    hDaemonInfoInOut = di;
648cc290419Sopenharmony_ci                    break;
649cc290419Sopenharmony_ci                }
650cc290419Sopenharmony_ci            }
651cc290419Sopenharmony_ci            lockMapDaemon.unlock();
652cc290419Sopenharmony_ci            break;
653cc290419Sopenharmony_ci        }
654cc290419Sopenharmony_ci        case OP_WAIT_FOR_ANY: {
655cc290419Sopenharmony_ci            lockMapDaemon.lock();
656cc290419Sopenharmony_ci            map<string, HDaemonInfo>::iterator iter;
657cc290419Sopenharmony_ci            for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
658cc290419Sopenharmony_ci                HDaemonInfo di = iter->second;
659cc290419Sopenharmony_ci                if (di->connStatus == STATUS_CONNECTED) {
660cc290419Sopenharmony_ci                    hDaemonInfoInOut = di;
661cc290419Sopenharmony_ci                    break;
662cc290419Sopenharmony_ci                }
663cc290419Sopenharmony_ci            }
664cc290419Sopenharmony_ci            lockMapDaemon.unlock();
665cc290419Sopenharmony_ci            break;
666cc290419Sopenharmony_ci        }
667cc290419Sopenharmony_ci        case OP_UPDATE: {  // Cannot update the Object HDi lower key value by direct value
668cc290419Sopenharmony_ci            lockMapDaemon.lock();
669cc290419Sopenharmony_ci            HDaemonInfo hdi = mapDaemon[hDaemonInfoInOut->connectKey];
670cc290419Sopenharmony_ci            if (hdi) {
671cc290419Sopenharmony_ci                *mapDaemon[hDaemonInfoInOut->connectKey] = *hDaemonInfoInOut;
672cc290419Sopenharmony_ci            }
673cc290419Sopenharmony_ci            lockMapDaemon.unlock();
674cc290419Sopenharmony_ci            break;
675cc290419Sopenharmony_ci        }
676cc290419Sopenharmony_ci        default:
677cc290419Sopenharmony_ci            break;
678cc290419Sopenharmony_ci    }
679cc290419Sopenharmony_ci    return sRet;
680cc290419Sopenharmony_ci}
681cc290419Sopenharmony_ci}