1cc290419Sopenharmony_ci/*
2cc290419Sopenharmony_ci * Copyright (C) 2021 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 "daemon_usb.h"
16cc290419Sopenharmony_ci#include <cerrno>
17cc290419Sopenharmony_ci#include <cstddef>
18cc290419Sopenharmony_ci#include "arpa/inet.h"
19cc290419Sopenharmony_ci#include "asm-generic/int-ll64.h"
20cc290419Sopenharmony_ci#include "fcntl.h"
21cc290419Sopenharmony_ci#include "linux/usb/functionfs.h"
22cc290419Sopenharmony_ci#include "new"
23cc290419Sopenharmony_ci#include "sched.h"
24cc290419Sopenharmony_ci#include "system_depend.h"
25cc290419Sopenharmony_ci#include "unistd.h"
26cc290419Sopenharmony_ci#include "uv/unix.h"
27cc290419Sopenharmony_ci#include "daemon.h"
28cc290419Sopenharmony_ci#include "usb_ffs.h"
29cc290419Sopenharmony_ci
30cc290419Sopenharmony_cinamespace Hdc {
31cc290419Sopenharmony_cistatic constexpr int CONFIG_COUNT2 = 2;
32cc290419Sopenharmony_cistatic constexpr int CONFIG_COUNT3 = 3;
33cc290419Sopenharmony_cistatic constexpr int CONFIG_COUNT5 = 5;
34cc290419Sopenharmony_ci
35cc290419Sopenharmony_cistruct UvData {
36cc290419Sopenharmony_ci    HdcDaemonUSB *daemonUsb;
37cc290419Sopenharmony_ci    const uint8_t *buf;
38cc290419Sopenharmony_ci};
39cc290419Sopenharmony_ci
40cc290419Sopenharmony_ciHdcDaemonUSB::HdcDaemonUSB(const bool serverOrDaemonIn, void *ptrMainBase)
41cc290419Sopenharmony_ci    : HdcUSBBase(serverOrDaemonIn, ptrMainBase)
42cc290419Sopenharmony_ci{
43cc290419Sopenharmony_ci}
44cc290419Sopenharmony_ci
45cc290419Sopenharmony_ciHdcDaemonUSB::~HdcDaemonUSB()
46cc290419Sopenharmony_ci{
47cc290419Sopenharmony_ci    // Closed in the IO loop, no longer closing CLOSE ENDPOINT
48cc290419Sopenharmony_ci    Base::CloseFd(controlEp);
49cc290419Sopenharmony_ci    if (ctxRecv.buf) {
50cc290419Sopenharmony_ci        delete[] ctxRecv.buf;
51cc290419Sopenharmony_ci    }
52cc290419Sopenharmony_ci    uv_fs_req_cleanup(&ctxRecv.req);
53cc290419Sopenharmony_ci}
54cc290419Sopenharmony_ci
55cc290419Sopenharmony_civoid HdcDaemonUSB::Stop()
56cc290419Sopenharmony_ci{
57cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop");
58cc290419Sopenharmony_ci    // Here only clean up the IO-related resources, session related resources clear reason to clean up the session
59cc290419Sopenharmony_ci    // module
60cc290419Sopenharmony_ci    modRunning = false;
61cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop free main session");
62cc290419Sopenharmony_ci    Base::TryCloseHandle((uv_handle_t *)&checkEP);
63cc290419Sopenharmony_ci    CloseEndpoint(&usbHandle);
64cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop free main session finish");
65cc290419Sopenharmony_ci}
66cc290419Sopenharmony_ci
67cc290419Sopenharmony_cistring HdcDaemonUSB::GetDevPath(const std::string &path)
68cc290419Sopenharmony_ci{
69cc290419Sopenharmony_ci    DIR *dir = ::opendir(path.c_str());
70cc290419Sopenharmony_ci    if (dir == nullptr) {
71cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "%s: cannot open devpath: errno: %d", path.c_str(), errno);
72cc290419Sopenharmony_ci        return "";
73cc290419Sopenharmony_ci    }
74cc290419Sopenharmony_ci
75cc290419Sopenharmony_ci    string res = USB_FFS_BASE;
76cc290419Sopenharmony_ci    string node;
77cc290419Sopenharmony_ci    int count = 0;
78cc290419Sopenharmony_ci    struct dirent *entry = nullptr;
79cc290419Sopenharmony_ci    while ((entry = ::readdir(dir))) {
80cc290419Sopenharmony_ci        if (*entry->d_name == '.') {
81cc290419Sopenharmony_ci            continue;
82cc290419Sopenharmony_ci        }
83cc290419Sopenharmony_ci        node = entry->d_name;
84cc290419Sopenharmony_ci        ++count;
85cc290419Sopenharmony_ci    }
86cc290419Sopenharmony_ci    if (count > 1) {
87cc290419Sopenharmony_ci        res += "hdc";
88cc290419Sopenharmony_ci    } else {
89cc290419Sopenharmony_ci        res += node;
90cc290419Sopenharmony_ci    }
91cc290419Sopenharmony_ci    ::closedir(dir);
92cc290419Sopenharmony_ci    return res;
93cc290419Sopenharmony_ci}
94cc290419Sopenharmony_ci
95cc290419Sopenharmony_ciint HdcDaemonUSB::GetMaxPacketSize(int fdFfs)
96cc290419Sopenharmony_ci{
97cc290419Sopenharmony_ci    // no ioctl support, todo dynamic get
98cc290419Sopenharmony_ci    return MAX_PACKET_SIZE_HISPEED;
99cc290419Sopenharmony_ci}
100cc290419Sopenharmony_ci
101cc290419Sopenharmony_ciint HdcDaemonUSB::Initial()
102cc290419Sopenharmony_ci{
103cc290419Sopenharmony_ci    // after Linux-3.8,kernel switch to the USB Function FS
104cc290419Sopenharmony_ci    // Implement USB hdc function in user space
105cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB init");
106cc290419Sopenharmony_ci    basePath = GetDevPath(USB_FFS_BASE);
107cc290419Sopenharmony_ci    if (access((basePath + "/ep0").c_str(), F_OK) != 0) {
108cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG,"Only support usb-ffs, make sure kernel3.8+ and usb-ffs enabled, "
109cc290419Sopenharmony_ci                  "usbmode disabled: errno: %d, basePath: %s ", errno, basePath.c_str());
110cc290419Sopenharmony_ci        return ERR_API_FAIL;
111cc290419Sopenharmony_ci    }
112cc290419Sopenharmony_ci    ctxRecv.thisClass = this;
113cc290419Sopenharmony_ci    ctxRecv.bufSizeMax = Base::GetUsbffsBulkSize();
114cc290419Sopenharmony_ci    ctxRecv.buf = new uint8_t[ctxRecv.bufSizeMax]();
115cc290419Sopenharmony_ci    if (!ctxRecv.buf) {
116cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "Init alloc memory failed");
117cc290419Sopenharmony_ci        return ERR_BUF_ALLOC;
118cc290419Sopenharmony_ci    }
119cc290419Sopenharmony_ci
120cc290419Sopenharmony_ci    HdcDaemon *daemon = (HdcDaemon *)clsMainBase;
121cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB::Initiall");
122cc290419Sopenharmony_ci    uv_timer_init(&daemon->loopMain, &checkEP);
123cc290419Sopenharmony_ci    checkEP.data = this;
124cc290419Sopenharmony_ci    uv_timer_start(&checkEP, WatchEPTimer, 0, TIME_BASE);
125cc290419Sopenharmony_ci    return 0;
126cc290419Sopenharmony_ci}
127cc290419Sopenharmony_ci
128cc290419Sopenharmony_ci// make gnuc++ happy. Clang support direct assignment value to structure, buf g++ weakness
129cc290419Sopenharmony_civoid HdcDaemonUSB::FillUsbV2Head(UsbFunctionfsDescV2 &descUsbFfs)
130cc290419Sopenharmony_ci{
131cc290419Sopenharmony_ci    descUsbFfs.head.magic = LONG_LE(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
132cc290419Sopenharmony_ci    descUsbFfs.head.length = LONG_LE(sizeof(descUsbFfs));
133cc290419Sopenharmony_ci    descUsbFfs.head.flags
134cc290419Sopenharmony_ci        = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC | FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
135cc290419Sopenharmony_ci    descUsbFfs.config1Count = CONFIG_COUNT3;
136cc290419Sopenharmony_ci    descUsbFfs.config2Count = CONFIG_COUNT3;
137cc290419Sopenharmony_ci    descUsbFfs.config3Count = CONFIG_COUNT5;
138cc290419Sopenharmony_ci    descUsbFfs.configWosCount = CONFIG_COUNT2;
139cc290419Sopenharmony_ci    descUsbFfs.config1Desc = config1;
140cc290419Sopenharmony_ci    descUsbFfs.config2Desc = config2;
141cc290419Sopenharmony_ci    descUsbFfs.config3Desc = config3;
142cc290419Sopenharmony_ci    descUsbFfs.wosHead = g_wosHead;
143cc290419Sopenharmony_ci    descUsbFfs.wosDesc = g_wosDesc;
144cc290419Sopenharmony_ci    descUsbFfs.osPropHead = g_osPropHead;
145cc290419Sopenharmony_ci    descUsbFfs.osPropValues = g_osPropValues;
146cc290419Sopenharmony_ci}
147cc290419Sopenharmony_ci
148cc290419Sopenharmony_ci// DAEMON end USB module USB-FFS EP port connection
149cc290419Sopenharmony_ciint HdcDaemonUSB::ConnectEPPoint(HUSB hUSB)
150cc290419Sopenharmony_ci{
151cc290419Sopenharmony_ci    int ret = ERR_GENERIC;
152cc290419Sopenharmony_ci    struct UsbFunctionfsDescV2 descUsbFfs = {};
153cc290419Sopenharmony_ci    FillUsbV2Head(descUsbFfs);
154cc290419Sopenharmony_ci    while (true) {
155cc290419Sopenharmony_ci        if (controlEp <= 0) {
156cc290419Sopenharmony_ci            // After the control port sends the instruction, the device is initialized by the device to the HOST host,
157cc290419Sopenharmony_ci            // which can be found for USB devices. Do not send initialization to the EP0 control port, the USB
158cc290419Sopenharmony_ci            // device will not be initialized by Host
159cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "Begin send to control(EP0) for usb descriptor init");
160cc290419Sopenharmony_ci            string ep0Path = basePath + "/ep0";
161cc290419Sopenharmony_ci            if ((controlEp = open(ep0Path.c_str(), O_RDWR)) < 0) {
162cc290419Sopenharmony_ci                WRITE_LOG(LOG_WARN, "%s: cannot open control endpoint: errno=%d", ep0Path.c_str(), errno);
163cc290419Sopenharmony_ci                break;
164cc290419Sopenharmony_ci            }
165cc290419Sopenharmony_ci            if (write(controlEp, &descUsbFfs, sizeof(descUsbFfs)) < 0) {
166cc290419Sopenharmony_ci                WRITE_LOG(LOG_WARN, "%s: write ffs configs failed: errno=%d", ep0Path.c_str(), errno);
167cc290419Sopenharmony_ci                break;
168cc290419Sopenharmony_ci            }
169cc290419Sopenharmony_ci            if (write(controlEp, &USB_FFS_VALUE, sizeof(USB_FFS_VALUE)) < 0) {
170cc290419Sopenharmony_ci                WRITE_LOG(LOG_WARN, "%s: write USB_FFS_VALUE failed: errno=%d", ep0Path.c_str(), errno);
171cc290419Sopenharmony_ci                break;
172cc290419Sopenharmony_ci            }
173cc290419Sopenharmony_ci            // active usbrc,Send USB initialization signal
174cc290419Sopenharmony_ci            SystemDepend::SetDevItem("sys.usb.ffs.ready.hdc", "0");
175cc290419Sopenharmony_ci            SystemDepend::SetDevItem("sys.usb.ffs.ready", "1");
176cc290419Sopenharmony_ci            SystemDepend::SetDevItem("sys.usb.ffs.ready.hdc", "1");
177cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "ConnectEPPoint ctrl init finish, set usb-ffs ready");
178cc290419Sopenharmony_ci        }
179cc290419Sopenharmony_ci        string outPath = basePath + "/ep1";
180cc290419Sopenharmony_ci        if ((hUSB->bulkOut = open(outPath.c_str(), O_RDWR)) < 0) {
181cc290419Sopenharmony_ci            WRITE_LOG(LOG_WARN, "%s: cannot open bulk-out ep: errno=%d", outPath.c_str(), errno);
182cc290419Sopenharmony_ci            break;
183cc290419Sopenharmony_ci        }
184cc290419Sopenharmony_ci        string inPath = basePath + "/ep2";
185cc290419Sopenharmony_ci        if ((hUSB->bulkIn = open(inPath.c_str(), O_RDWR)) < 0) {
186cc290419Sopenharmony_ci            WRITE_LOG(LOG_WARN, "%s: cannot open bulk-in ep: errno=%d", inPath.c_str(), errno);
187cc290419Sopenharmony_ci            break;
188cc290419Sopenharmony_ci        }
189cc290419Sopenharmony_ci        // cannot open with O_CLOEXEC, must fcntl
190cc290419Sopenharmony_ci        fcntl(controlEp, F_SETFD, FD_CLOEXEC);
191cc290419Sopenharmony_ci        fcntl(hUSB->bulkOut, F_SETFD, FD_CLOEXEC);
192cc290419Sopenharmony_ci        fcntl(hUSB->bulkIn, F_SETFD, FD_CLOEXEC);
193cc290419Sopenharmony_ci        hUSB->wMaxPacketSizeSend = GetMaxPacketSize(hUSB->bulkIn);
194cc290419Sopenharmony_ci
195cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "New bulk in\\out open bulkout:%d bulkin:%d", hUSB->bulkOut, hUSB->bulkIn);
196cc290419Sopenharmony_ci        ret = RET_SUCCESS;
197cc290419Sopenharmony_ci        break;
198cc290419Sopenharmony_ci    }
199cc290419Sopenharmony_ci    if (ret != RET_SUCCESS) {
200cc290419Sopenharmony_ci        CloseEndpoint(hUSB, true);
201cc290419Sopenharmony_ci    }
202cc290419Sopenharmony_ci    return ret;
203cc290419Sopenharmony_ci}
204cc290419Sopenharmony_ci
205cc290419Sopenharmony_civoid HdcDaemonUSB::CloseEndpoint(HUSB hUSB, bool closeCtrlEp)
206cc290419Sopenharmony_ci{
207cc290419Sopenharmony_ci    Base::CloseFd(hUSB->bulkIn);
208cc290419Sopenharmony_ci    Base::CloseFd(hUSB->bulkOut);
209cc290419Sopenharmony_ci    if (controlEp > 0 && closeCtrlEp) {
210cc290419Sopenharmony_ci        Base::CloseFd(controlEp);
211cc290419Sopenharmony_ci        controlEp = 0;
212cc290419Sopenharmony_ci    }
213cc290419Sopenharmony_ci    isAlive = false;
214cc290419Sopenharmony_ci    WRITE_LOG(LOG_FATAL, "DaemonUSB close endpoint");
215cc290419Sopenharmony_ci}
216cc290419Sopenharmony_ci
217cc290419Sopenharmony_civoid HdcDaemonUSB::ResetOldSession(uint32_t sessionId, bool isSoftReset)
218cc290419Sopenharmony_ci{
219cc290419Sopenharmony_ci    HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
220cc290419Sopenharmony_ci    if (sessionId == 0) {
221cc290419Sopenharmony_ci        sessionId = currentSessionId;
222cc290419Sopenharmony_ci    }
223cc290419Sopenharmony_ci    HSession hSession = daemon->AdminSession(OP_QUERY, sessionId, nullptr);
224cc290419Sopenharmony_ci    if (hSession == nullptr) {
225cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "ResetOldSession hSession nullptr sessionId:%u", sessionId);
226cc290419Sopenharmony_ci        return;
227cc290419Sopenharmony_ci    }
228cc290419Sopenharmony_ci    // The Host side is restarted, but the USB cable is still connected
229cc290419Sopenharmony_ci    hSession->isSoftReset = isSoftReset;
230cc290419Sopenharmony_ci    WRITE_LOG(LOG_WARN, "Hostside softreset to restart daemon, old sessionId:%u isSoftReset:%d",
231cc290419Sopenharmony_ci        sessionId, isSoftReset);
232cc290419Sopenharmony_ci    daemon->FreeSession(sessionId);
233cc290419Sopenharmony_ci}
234cc290419Sopenharmony_ci
235cc290419Sopenharmony_ci// Prevent other USB data misfortunes to send the program crash
236cc290419Sopenharmony_ciint HdcDaemonUSB::AvailablePacket(uint8_t *ioBuf, int ioBytes, uint32_t *sessionId)
237cc290419Sopenharmony_ci{
238cc290419Sopenharmony_ci    int ret = RET_SUCCESS;
239cc290419Sopenharmony_ci    while (true) {
240cc290419Sopenharmony_ci        if (!IsUsbPacketHeader(ioBuf, ioBytes)) {
241cc290419Sopenharmony_ci            break;
242cc290419Sopenharmony_ci        }
243cc290419Sopenharmony_ci        // usb header
244cc290419Sopenharmony_ci        USBHead *usbPayloadHeader = reinterpret_cast<struct USBHead *>(ioBuf);
245cc290419Sopenharmony_ci        uint32_t inSessionId = ntohl(usbPayloadHeader->sessionId);
246cc290419Sopenharmony_ci        if ((usbPayloadHeader->option & USB_OPTION_RESET)) {
247cc290419Sopenharmony_ci            WRITE_LOG(LOG_INFO, "USB_OPTION_RESET inSessionId:%u, currentSessionId:%u",
248cc290419Sopenharmony_ci                inSessionId, currentSessionId);
249cc290419Sopenharmony_ci            ResetOldSession(inSessionId, true);
250cc290419Sopenharmony_ci            ret = ERR_IO_SOFT_RESET;
251cc290419Sopenharmony_ci            break;
252cc290419Sopenharmony_ci        }
253cc290419Sopenharmony_ci        *sessionId = inSessionId;
254cc290419Sopenharmony_ci        break;
255cc290419Sopenharmony_ci    }
256cc290419Sopenharmony_ci    return ret;
257cc290419Sopenharmony_ci}
258cc290419Sopenharmony_ci
259cc290419Sopenharmony_ci// Work in subcrete,Work thread is ready
260cc290419Sopenharmony_cibool HdcDaemonUSB::ReadyForWorkThread(HSession hSession)
261cc290419Sopenharmony_ci{
262cc290419Sopenharmony_ci    HdcUSBBase::ReadyForWorkThread(hSession);
263cc290419Sopenharmony_ci    return true;
264cc290419Sopenharmony_ci};
265cc290419Sopenharmony_ci
266cc290419Sopenharmony_ciint HdcDaemonUSB::CloseBulkEp(bool bulkInOut, int bulkFd, uv_loop_t *loop)
267cc290419Sopenharmony_ci{
268cc290419Sopenharmony_ci    struct CtxCloseBulkEp {
269cc290419Sopenharmony_ci        uv_fs_t req;
270cc290419Sopenharmony_ci        HdcDaemonUSB *thisClass;
271cc290419Sopenharmony_ci        bool bulkInOut;
272cc290419Sopenharmony_ci    };
273cc290419Sopenharmony_ci    CtxCloseBulkEp *ctx = new(std::nothrow) CtxCloseBulkEp();
274cc290419Sopenharmony_ci    if (ctx == nullptr) {
275cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "CloseBulkEp new ctx failed");
276cc290419Sopenharmony_ci        return -1;
277cc290419Sopenharmony_ci    }
278cc290419Sopenharmony_ci    uv_fs_t *req = &ctx->req;
279cc290419Sopenharmony_ci    req->data = ctx;
280cc290419Sopenharmony_ci    ctx->bulkInOut = bulkInOut;
281cc290419Sopenharmony_ci    ctx->thisClass = this;
282cc290419Sopenharmony_ci    isAlive = false;
283cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "CloseBulkEp bulkFd:%d", bulkFd);
284cc290419Sopenharmony_ci    uv_fs_close(loop, req, bulkFd, [](uv_fs_t *req) {
285cc290419Sopenharmony_ci        auto ctx = (CtxCloseBulkEp *)req->data;
286cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "Try to abort blukin write callback %s", ctx->bulkInOut ? "bulkin" : "bulkout");
287cc290419Sopenharmony_ci        if (ctx->bulkInOut) {
288cc290419Sopenharmony_ci            ctx->thisClass->usbHandle.bulkIn = 0;
289cc290419Sopenharmony_ci        } else {
290cc290419Sopenharmony_ci            ctx->thisClass->usbHandle.bulkOut = 0;
291cc290419Sopenharmony_ci        }
292cc290419Sopenharmony_ci        uv_fs_req_cleanup(req);
293cc290419Sopenharmony_ci        delete ctx;
294cc290419Sopenharmony_ci    });
295cc290419Sopenharmony_ci    return 0;
296cc290419Sopenharmony_ci}
297cc290419Sopenharmony_ci
298cc290419Sopenharmony_ciint HdcDaemonUSB::SendUSBIOSync(HSession hSession, HUSB hMainUSB, const uint8_t *data, const int length)
299cc290419Sopenharmony_ci{
300cc290419Sopenharmony_ci    int bulkIn = hMainUSB->bulkIn;
301cc290419Sopenharmony_ci    int childRet = 0;
302cc290419Sopenharmony_ci    int ret = ERR_IO_FAIL;
303cc290419Sopenharmony_ci    int offset = 0;
304cc290419Sopenharmony_ci    StartTraceScope("HdcDaemonUSB::SendUSBIOSync");
305cc290419Sopenharmony_ci    while (modRunning && isAlive && !hSession->isDead) {
306cc290419Sopenharmony_ci        childRet = write(bulkIn, const_cast<uint8_t *>(data) + offset, length - offset);
307cc290419Sopenharmony_ci        if (childRet <= 0) {
308cc290419Sopenharmony_ci            int err = errno;
309cc290419Sopenharmony_ci            if (err == EINTR) {
310cc290419Sopenharmony_ci                WRITE_LOG(LOG_WARN, "BulkinWrite write EINTR, try again, offset:%u bulkIn:%d bulkOut:%d",
311cc290419Sopenharmony_ci                    offset, bulkIn, hMainUSB->bulkOut);
312cc290419Sopenharmony_ci                continue;
313cc290419Sopenharmony_ci            } else {
314cc290419Sopenharmony_ci                WRITE_LOG(LOG_FATAL, "BulkinWrite write fatal errno %d", err);
315cc290419Sopenharmony_ci                isAlive = false;
316cc290419Sopenharmony_ci            }
317cc290419Sopenharmony_ci            break;
318cc290419Sopenharmony_ci        }
319cc290419Sopenharmony_ci        offset += childRet;
320cc290419Sopenharmony_ci        if (offset >= length) {
321cc290419Sopenharmony_ci            break;
322cc290419Sopenharmony_ci        }
323cc290419Sopenharmony_ci    }
324cc290419Sopenharmony_ci    if (offset == length) {
325cc290419Sopenharmony_ci        ret = length;
326cc290419Sopenharmony_ci    } else {
327cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "BulkinWrite write failed, nsize:%d really:%d modRunning:%d isAlive:%d SessionDead:%d",
328cc290419Sopenharmony_ci                  length, offset, modRunning, isAlive, hSession->isDead);
329cc290419Sopenharmony_ci    }
330cc290419Sopenharmony_ci    return ret;
331cc290419Sopenharmony_ci}
332cc290419Sopenharmony_ci
333cc290419Sopenharmony_ciint HdcDaemonUSB::SendUSBRaw(HSession hSession, uint8_t *data, const int length)
334cc290419Sopenharmony_ci{
335cc290419Sopenharmony_ci    StartTraceScope("HdcDaemonUSB::SendUSBRaw");
336cc290419Sopenharmony_ci    HdcDaemon *daemon = (HdcDaemon *)hSession->classInstance;
337cc290419Sopenharmony_ci    uint32_t sessionId = hSession->sessionId;
338cc290419Sopenharmony_ci    std::unique_lock<std::mutex> lock(mutexUsbFfs);
339cc290419Sopenharmony_ci    if (Base::IsSessionDeleted(sessionId)) {
340cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "SendUSBRaw session %u is deleted", sessionId);
341cc290419Sopenharmony_ci        return ERR_SESSION_DEAD;
342cc290419Sopenharmony_ci    }
343cc290419Sopenharmony_ci    ++hSession->ref;
344cc290419Sopenharmony_ci    int ret = SendUSBIOSync(hSession, &usbHandle, data, length);
345cc290419Sopenharmony_ci    --hSession->ref;
346cc290419Sopenharmony_ci    if (ret < 0) {
347cc290419Sopenharmony_ci        daemon->FreeSession(hSession->sessionId);
348cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "SendUSBRaw try to freesession");
349cc290419Sopenharmony_ci    }
350cc290419Sopenharmony_ci    return ret;
351cc290419Sopenharmony_ci}
352cc290419Sopenharmony_ci
353cc290419Sopenharmony_ci// cross thread call
354cc290419Sopenharmony_civoid HdcDaemonUSB::OnNewHandshakeOK(const uint32_t sessionId)
355cc290419Sopenharmony_ci{
356cc290419Sopenharmony_ci    currentSessionId = sessionId;  // sync with server, and set server's real Id
357cc290419Sopenharmony_ci}
358cc290419Sopenharmony_ci
359cc290419Sopenharmony_ci// MainThreadCall, when seession was freed
360cc290419Sopenharmony_civoid HdcDaemonUSB::OnSessionFreeFinally(const HSession hSession)
361cc290419Sopenharmony_ci{
362cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "OnSessionFreeFinally sid:%u currentsid:%u", hSession->sessionId, currentSessionId);
363cc290419Sopenharmony_ci    if (hSession->isSoftReset) {
364cc290419Sopenharmony_ci        WRITE_LOG(LOG_INFO, "OnSessionFreeFinally sid:%u softreset", hSession->sessionId);
365cc290419Sopenharmony_ci        return;
366cc290419Sopenharmony_ci    }
367cc290419Sopenharmony_ci    if (currentSessionId == hSession->sessionId) {
368cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "OnSessionFreeFinally set isAlive false");
369cc290419Sopenharmony_ci        isAlive = false;
370cc290419Sopenharmony_ci        // uv_cancel ctxRecv.req == UV_EBUSY, not effect immediately. It must be close by logic
371cc290419Sopenharmony_ci    }
372cc290419Sopenharmony_ci}
373cc290419Sopenharmony_ci
374cc290419Sopenharmony_ciHSession HdcDaemonUSB::PrepareNewSession(uint32_t sessionId, uint8_t *pRecvBuf, int recvBytesIO)
375cc290419Sopenharmony_ci{
376cc290419Sopenharmony_ci    HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
377cc290419Sopenharmony_ci    StartTraceScope("HdcDaemonUSB::PrepareNewSession");
378cc290419Sopenharmony_ci    HSession hChildSession = daemon->MallocSession(false, CONN_USB, this, sessionId);
379cc290419Sopenharmony_ci    if (!hChildSession) {
380cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "malloc session failed sessionId:%u", sessionId);
381cc290419Sopenharmony_ci        return nullptr;
382cc290419Sopenharmony_ci    }
383cc290419Sopenharmony_ci    currentSessionId = sessionId;
384cc290419Sopenharmony_ci    Base::StartWorkThread(&daemon->loopMain, daemon->SessionWorkThread, Base::FinishWorkThread, hChildSession);
385cc290419Sopenharmony_ci
386cc290419Sopenharmony_ci    HSessionInfo hSessionInfo = new(std::nothrow) HdcSessionInfo();
387cc290419Sopenharmony_ci    if (hSessionInfo == nullptr) {
388cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "PrepareNewSession new hSessionInfo failed");
389cc290419Sopenharmony_ci        return nullptr;
390cc290419Sopenharmony_ci    }
391cc290419Sopenharmony_ci    hSessionInfo->sessionId = hChildSession->sessionId;
392cc290419Sopenharmony_ci    hSessionInfo->classInstance = hChildSession->classInstance;
393cc290419Sopenharmony_ci    hSessionInfo->classModule = hChildSession->classModule;
394cc290419Sopenharmony_ci    hSessionInfo->hSession = hChildSession;
395cc290419Sopenharmony_ci    auto funcNewSessionUp = [](uv_timer_t *handle) -> void {
396cc290419Sopenharmony_ci        HSessionInfo hSessionInfo = reinterpret_cast<HSessionInfo>(handle->data);
397cc290419Sopenharmony_ci        if (hSessionInfo == nullptr) {
398cc290419Sopenharmony_ci            Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(handle), Base::CloseTimerCallback);
399cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "hSessionInfo is null");
400cc290419Sopenharmony_ci            return;
401cc290419Sopenharmony_ci        }
402cc290419Sopenharmony_ci        HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(hSessionInfo->classInstance);
403cc290419Sopenharmony_ci        if (Base::IsSessionDeleted(hSessionInfo->sessionId)) {
404cc290419Sopenharmony_ci            WRITE_LOG(LOG_INFO, "funcNewSessionUp session is deleted");
405cc290419Sopenharmony_ci            delete hSessionInfo;
406cc290419Sopenharmony_ci            handle->data = nullptr;
407cc290419Sopenharmony_ci            Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(handle), Base::CloseTimerCallback);
408cc290419Sopenharmony_ci            return;
409cc290419Sopenharmony_ci        }
410cc290419Sopenharmony_ci        HSession hChildSession = hSessionInfo->hSession;
411cc290419Sopenharmony_ci        if (hChildSession->childLoop.active_handles == 0) {
412cc290419Sopenharmony_ci            return;
413cc290419Sopenharmony_ci        }
414cc290419Sopenharmony_ci        if (!hChildSession->isDead) {
415cc290419Sopenharmony_ci            auto ctrl = daemon->BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
416cc290419Sopenharmony_ci            Base::SendToPollFd(hChildSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
417cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "Main thread usbio migrate finish");
418cc290419Sopenharmony_ci        }
419cc290419Sopenharmony_ci        delete hSessionInfo;
420cc290419Sopenharmony_ci        handle->data = nullptr;
421cc290419Sopenharmony_ci        Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(handle), Base::CloseTimerCallback);
422cc290419Sopenharmony_ci    };
423cc290419Sopenharmony_ci    Base::TimerUvTask(&daemon->loopMain, hSessionInfo, funcNewSessionUp);
424cc290419Sopenharmony_ci    return hChildSession;
425cc290419Sopenharmony_ci}
426cc290419Sopenharmony_ci
427cc290419Sopenharmony_civoid HdcDaemonUSB::UvWriteCallback(uv_write_t *req, int status)
428cc290419Sopenharmony_ci{
429cc290419Sopenharmony_ci    StartTraceScope("HdcDaemonUSB::UvWriteCallback");
430cc290419Sopenharmony_ci    if (status < 0) {
431cc290419Sopenharmony_ci        constexpr int bufSize = 1024;
432cc290419Sopenharmony_ci        char buf[bufSize] = { 0 };
433cc290419Sopenharmony_ci        uv_strerror_r(status, buf, bufSize);
434cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "SendCallback failed,status:%d %s", status, buf);
435cc290419Sopenharmony_ci    }
436cc290419Sopenharmony_ci    UvData *uvData = reinterpret_cast<UvData *>(req->data);
437cc290419Sopenharmony_ci    if (uvData) {
438cc290419Sopenharmony_ci#ifndef CONFIG_USE_JEMALLOC_DFX_INIF
439cc290419Sopenharmony_ci        uvData->daemonUsb->cirbuf.Free(uvData->buf);
440cc290419Sopenharmony_ci#else
441cc290419Sopenharmony_ci        delete[] uvData->buf;
442cc290419Sopenharmony_ci#endif
443cc290419Sopenharmony_ci        delete uvData;
444cc290419Sopenharmony_ci    }
445cc290419Sopenharmony_ci    delete req;
446cc290419Sopenharmony_ci}
447cc290419Sopenharmony_ci
448cc290419Sopenharmony_ciint HdcDaemonUSB::UsbToStream(uv_stream_t *stream, const uint8_t *buf, const int size)
449cc290419Sopenharmony_ci{
450cc290419Sopenharmony_ci    StartTraceScope("HdcDaemonUSB::UsbToStream");
451cc290419Sopenharmony_ci    int ret = ERR_GENERIC;
452cc290419Sopenharmony_ci    uv_write_t *reqWrite = new uv_write_t();
453cc290419Sopenharmony_ci    if (!reqWrite) {
454cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "UsbToStream new write_t failed size:%d", size);
455cc290419Sopenharmony_ci#ifndef CONFIG_USE_JEMALLOC_DFX_INIF
456cc290419Sopenharmony_ci        cirbuf.Free(buf);
457cc290419Sopenharmony_ci#else
458cc290419Sopenharmony_ci        delete[] buf;
459cc290419Sopenharmony_ci#endif
460cc290419Sopenharmony_ci        return ERR_BUF_ALLOC;
461cc290419Sopenharmony_ci    }
462cc290419Sopenharmony_ci    uv_buf_t bfr;
463cc290419Sopenharmony_ci    while (true) {
464cc290419Sopenharmony_ci        UvData *uvData = new(std::nothrow) UvData();
465cc290419Sopenharmony_ci        if (uvData == nullptr) {
466cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "UsbToStream new uvData failed size:%d", size);
467cc290419Sopenharmony_ci#ifndef CONFIG_USE_JEMALLOC_DFX_INIF
468cc290419Sopenharmony_ci            cirbuf.Free(buf);
469cc290419Sopenharmony_ci#else
470cc290419Sopenharmony_ci            delete[] buf;
471cc290419Sopenharmony_ci#endif
472cc290419Sopenharmony_ci            delete reqWrite;
473cc290419Sopenharmony_ci            return ERR_BUF_ALLOC;
474cc290419Sopenharmony_ci        }
475cc290419Sopenharmony_ci        uvData->daemonUsb = this;
476cc290419Sopenharmony_ci        uvData->buf = buf;
477cc290419Sopenharmony_ci        reqWrite->data = reinterpret_cast<void *>(uvData);
478cc290419Sopenharmony_ci        bfr.base = (char *)buf;
479cc290419Sopenharmony_ci        bfr.len = size;
480cc290419Sopenharmony_ci        if (!uv_is_writable(stream)) {
481cc290419Sopenharmony_ci            WRITE_LOG(LOG_WARN, "UsbToStream uv_is_writable false size:%d", size);
482cc290419Sopenharmony_ci            delete reqWrite;
483cc290419Sopenharmony_ci#ifndef CONFIG_USE_JEMALLOC_DFX_INIF
484cc290419Sopenharmony_ci            cirbuf.Free(buf);
485cc290419Sopenharmony_ci#else
486cc290419Sopenharmony_ci            delete[] buf;
487cc290419Sopenharmony_ci#endif
488cc290419Sopenharmony_ci            delete uvData;
489cc290419Sopenharmony_ci            break;
490cc290419Sopenharmony_ci        }
491cc290419Sopenharmony_ci        ret = uv_write(reqWrite, stream, &bfr, 1, UvWriteCallback);
492cc290419Sopenharmony_ci        if (ret < 0) {
493cc290419Sopenharmony_ci            WRITE_LOG(LOG_WARN, "UsbToStream uv_write false ret:%d", ret);
494cc290419Sopenharmony_ci            delete reqWrite;
495cc290419Sopenharmony_ci#ifndef CONFIG_USE_JEMALLOC_DFX_INIF
496cc290419Sopenharmony_ci            cirbuf.Free(buf);
497cc290419Sopenharmony_ci#else
498cc290419Sopenharmony_ci            delete[] buf;
499cc290419Sopenharmony_ci#endif
500cc290419Sopenharmony_ci            delete uvData;
501cc290419Sopenharmony_ci            ret = ERR_IO_FAIL;
502cc290419Sopenharmony_ci            break;
503cc290419Sopenharmony_ci        }
504cc290419Sopenharmony_ci        ret = size;
505cc290419Sopenharmony_ci        break;
506cc290419Sopenharmony_ci    }
507cc290419Sopenharmony_ci    return ret;
508cc290419Sopenharmony_ci}
509cc290419Sopenharmony_ci
510cc290419Sopenharmony_ciint HdcDaemonUSB::UsbToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize)
511cc290419Sopenharmony_ci{
512cc290419Sopenharmony_ci    StartTraceScope("HdcDaemonUSB::UsbToHdcProtocol");
513cc290419Sopenharmony_ci#ifndef CONFIG_USE_JEMALLOC_DFX_INIF
514cc290419Sopenharmony_ci    uint8_t *data = cirbuf.Malloc();
515cc290419Sopenharmony_ci#else
516cc290419Sopenharmony_ci    uint8_t *data = new uint8_t[dataSize];
517cc290419Sopenharmony_ci#endif
518cc290419Sopenharmony_ci    if (data == nullptr) {
519cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "UsbToHdcProtocol data nullptr");
520cc290419Sopenharmony_ci        return -1;
521cc290419Sopenharmony_ci    }
522cc290419Sopenharmony_ci    if (memcpy_s(data, dataSize, appendData, dataSize)) {
523cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "UsbToHdcProtocol memory copy failed dataSize:%d", dataSize);
524cc290419Sopenharmony_ci#ifndef CONFIG_USE_JEMALLOC_DFX_INIF
525cc290419Sopenharmony_ci        cirbuf.Free(data);
526cc290419Sopenharmony_ci#else
527cc290419Sopenharmony_ci        delete[] data;
528cc290419Sopenharmony_ci#endif
529cc290419Sopenharmony_ci        return ERR_BUF_COPY;
530cc290419Sopenharmony_ci    }
531cc290419Sopenharmony_ci    return UsbToStream(stream, data, dataSize);
532cc290419Sopenharmony_ci}
533cc290419Sopenharmony_ci
534cc290419Sopenharmony_ciint HdcDaemonUSB::DispatchToWorkThread(uint32_t sessionId, uint8_t *readBuf, int readBytes)
535cc290419Sopenharmony_ci{
536cc290419Sopenharmony_ci    HSession hChildSession = nullptr;
537cc290419Sopenharmony_ci    HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
538cc290419Sopenharmony_ci    int childRet = RET_SUCCESS;
539cc290419Sopenharmony_ci    StartTraceScope("HdcDaemonUSB::DispatchToWorkThread");
540cc290419Sopenharmony_ci    if (sessionId == 0) {
541cc290419Sopenharmony_ci        // hdc packet data
542cc290419Sopenharmony_ci        sessionId = currentSessionId;
543cc290419Sopenharmony_ci    }
544cc290419Sopenharmony_ci    if (currentSessionId != 0 && sessionId != currentSessionId) {
545cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "New session coming, restart old sessionId:%u", currentSessionId);
546cc290419Sopenharmony_ci        ResetOldSession(currentSessionId);
547cc290419Sopenharmony_ci        currentSessionId = 0;
548cc290419Sopenharmony_ci    }
549cc290419Sopenharmony_ci    hChildSession = daemon->AdminSession(OP_QUERY, sessionId, nullptr);
550cc290419Sopenharmony_ci    if (!hChildSession) {
551cc290419Sopenharmony_ci        hChildSession = PrepareNewSession(sessionId, readBuf, readBytes);
552cc290419Sopenharmony_ci        if (!hChildSession) {
553cc290419Sopenharmony_ci            WRITE_LOG(LOG_WARN, "prep new session err for sessionId:%u", sessionId);
554cc290419Sopenharmony_ci            return ERR_SESSION_NOFOUND;
555cc290419Sopenharmony_ci        }
556cc290419Sopenharmony_ci    }
557cc290419Sopenharmony_ci
558cc290419Sopenharmony_ci    if (hChildSession->childCleared || hChildSession->isDead) {
559cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "session dead clr:%d - %d", hChildSession->childCleared, hChildSession->isDead);
560cc290419Sopenharmony_ci        return ERR_SESSION_DEAD;
561cc290419Sopenharmony_ci    }
562cc290419Sopenharmony_ci    uv_stream_t *stream = reinterpret_cast<uv_stream_t *>(&hChildSession->dataPipe[STREAM_MAIN]);
563cc290419Sopenharmony_ci    if ((childRet = SendToHdcStream(hChildSession, stream, readBuf, readBytes)) < 0) {
564cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "DispatchToWorkThread SendToHdcStream err ret:%d", childRet);
565cc290419Sopenharmony_ci        return ERR_IO_FAIL;
566cc290419Sopenharmony_ci    }
567cc290419Sopenharmony_ci    return childRet;
568cc290419Sopenharmony_ci}
569cc290419Sopenharmony_ci
570cc290419Sopenharmony_cibool HdcDaemonUSB::JumpAntiquePacket(const uint8_t &buf, ssize_t bytes) const
571cc290419Sopenharmony_ci{
572cc290419Sopenharmony_ci    constexpr size_t antiqueFlagSize = 4;
573cc290419Sopenharmony_ci    constexpr size_t antiqueFullSize = 24;
574cc290419Sopenharmony_ci    // anti CNXN 0x4e584e43
575cc290419Sopenharmony_ci    uint8_t flag[] = { 0x43, 0x4e, 0x58, 0x4e };
576cc290419Sopenharmony_ci    if (bytes == antiqueFullSize && !memcmp(&buf, flag, antiqueFlagSize)) {
577cc290419Sopenharmony_ci        return true;
578cc290419Sopenharmony_ci    }
579cc290419Sopenharmony_ci    return false;
580cc290419Sopenharmony_ci}
581cc290419Sopenharmony_ci
582cc290419Sopenharmony_ci// Only physically swap EP ports will be reset
583cc290419Sopenharmony_civoid HdcDaemonUSB::OnUSBRead(uv_fs_t *req)
584cc290419Sopenharmony_ci{  // Only read at the main thread
585cc290419Sopenharmony_ci    StartTraceScope("HdcDaemonUSB::OnUSBRead");
586cc290419Sopenharmony_ci    auto ctxIo = reinterpret_cast<CtxUvFileCommonIo *>(req->data);
587cc290419Sopenharmony_ci    auto hUSB = reinterpret_cast<HUSB>(ctxIo->data);
588cc290419Sopenharmony_ci    auto thisClass = reinterpret_cast<HdcDaemonUSB *>(ctxIo->thisClass);
589cc290419Sopenharmony_ci    uint8_t *bufPtr = ctxIo->buf;
590cc290419Sopenharmony_ci    ssize_t bytesIOBytes = req->result;
591cc290419Sopenharmony_ci    uint32_t sessionId = 0;
592cc290419Sopenharmony_ci    bool ret = false;
593cc290419Sopenharmony_ci    int childRet = 0;
594cc290419Sopenharmony_ci    if (bytesIOBytes > hUSB->wMaxPacketSizeSend && bytesIOBytes != thisClass->saveNextReadSize) {
595cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "Not full packet, wanted:%d really:%d", thisClass->saveNextReadSize, bytesIOBytes);
596cc290419Sopenharmony_ci    }
597cc290419Sopenharmony_ci    while (thisClass->isAlive) {
598cc290419Sopenharmony_ci        // Don't care is module running, first deal with this
599cc290419Sopenharmony_ci        if (bytesIOBytes < 0) {
600cc290419Sopenharmony_ci            // logic alive and EINTER is gdb attach
601cc290419Sopenharmony_ci            //
602cc290419Sopenharmony_ci            // [about gdb attach known issue]
603cc290419Sopenharmony_ci            // When GDB debugging is loaded, the number of USB read interrupts of libuv will increase. Multiple
604cc290419Sopenharmony_ci            // interrupts will increase the correctness of USB data reading. Setting GDB to asynchronous mode or using
605cc290419Sopenharmony_ci            // log debugging can avoid this problem
606cc290419Sopenharmony_ci            if (bytesIOBytes != -EINTR) {  // Epoll will be broken when gdb attach
607cc290419Sopenharmony_ci                constexpr int bufSize = 1024;
608cc290419Sopenharmony_ci                char buf[bufSize] = { 0 };
609cc290419Sopenharmony_ci                uv_strerror_r(bytesIOBytes, buf, bufSize);
610cc290419Sopenharmony_ci                WRITE_LOG(LOG_WARN, "USBIO ret:%d failed:%s", bytesIOBytes, buf);
611cc290419Sopenharmony_ci                ret = false;
612cc290419Sopenharmony_ci                break;
613cc290419Sopenharmony_ci            } else {
614cc290419Sopenharmony_ci                WRITE_LOG(LOG_ALL, "OnUSBRead signal EINTR");
615cc290419Sopenharmony_ci            }
616cc290419Sopenharmony_ci        } else if (bytesIOBytes == 0) {  // zero packet
617cc290419Sopenharmony_ci            WRITE_LOG(LOG_ALL, "Zero packet received");
618cc290419Sopenharmony_ci        } else {
619cc290419Sopenharmony_ci            if (thisClass->JumpAntiquePacket(*bufPtr, bytesIOBytes)) {
620cc290419Sopenharmony_ci                WRITE_LOG(LOG_DEBUG, "JumpAntiquePacket auto jump");
621cc290419Sopenharmony_ci                ret = true;
622cc290419Sopenharmony_ci                break;
623cc290419Sopenharmony_ci            }
624cc290419Sopenharmony_ci            // guess is head of packet
625cc290419Sopenharmony_ci            if ((childRet = thisClass->AvailablePacket((uint8_t *)bufPtr, bytesIOBytes, &sessionId)) != RET_SUCCESS) {
626cc290419Sopenharmony_ci                if (childRet != ERR_IO_SOFT_RESET) {
627cc290419Sopenharmony_ci                    WRITE_LOG(LOG_WARN, "AvailablePacket check failed, ret:%d buf:%-50s", bytesIOBytes, bufPtr);
628cc290419Sopenharmony_ci                    break;
629cc290419Sopenharmony_ci                }
630cc290419Sopenharmony_ci                // reset packet
631cc290419Sopenharmony_ci                childRet = 0;  // need max size
632cc290419Sopenharmony_ci            } else {
633cc290419Sopenharmony_ci                // AvailablePacket case
634cc290419Sopenharmony_ci                if ((childRet = thisClass->DispatchToWorkThread(sessionId, bufPtr, bytesIOBytes)) < 0) {
635cc290419Sopenharmony_ci                    WRITE_LOG(LOG_FATAL, "DispatchToWorkThread failed");
636cc290419Sopenharmony_ci                    break;
637cc290419Sopenharmony_ci                }
638cc290419Sopenharmony_ci            }
639cc290419Sopenharmony_ci        }
640cc290419Sopenharmony_ci        int nextReadSize = childRet == 0 ? hUSB->wMaxPacketSizeSend : std::min(childRet, Base::GetUsbffsBulkSize());
641cc290419Sopenharmony_ci        thisClass->saveNextReadSize = nextReadSize;
642cc290419Sopenharmony_ci        if (thisClass->LoopUSBRead(hUSB, nextReadSize) < 0) {
643cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "LoopUSBRead failed");
644cc290419Sopenharmony_ci            break;
645cc290419Sopenharmony_ci        }
646cc290419Sopenharmony_ci        ret = true;
647cc290419Sopenharmony_ci        break;
648cc290419Sopenharmony_ci    }
649cc290419Sopenharmony_ci    if (!ret) {
650cc290419Sopenharmony_ci        WRITE_LOG(LOG_INFO, "OnUSBRead ret false, set isAlive = false");
651cc290419Sopenharmony_ci        thisClass->isAlive = false;
652cc290419Sopenharmony_ci        thisClass->ctxRecv.atPollQueue = false;
653cc290419Sopenharmony_ci    }
654cc290419Sopenharmony_ci}
655cc290419Sopenharmony_ci
656cc290419Sopenharmony_ciint HdcDaemonUSB::LoopUSBRead(HUSB hUSB, int readMaxWanted)
657cc290419Sopenharmony_ci{
658cc290419Sopenharmony_ci    StartTraceScope("HdcDaemonUSB::LoopUSBRead");
659cc290419Sopenharmony_ci    int ret = ERR_GENERIC;
660cc290419Sopenharmony_ci    HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
661cc290419Sopenharmony_ci    if (daemon == nullptr) {
662cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "daemon is nullptr in LoopUSBRead");
663cc290419Sopenharmony_ci        return ret;
664cc290419Sopenharmony_ci    }
665cc290419Sopenharmony_ci    uv_buf_t iov;
666cc290419Sopenharmony_ci    ctxRecv.data = hUSB;
667cc290419Sopenharmony_ci    ctxRecv.bufSize = readMaxWanted;
668cc290419Sopenharmony_ci    ctxRecv.req = {};
669cc290419Sopenharmony_ci    uv_fs_t *req = &ctxRecv.req;
670cc290419Sopenharmony_ci    req->data = &ctxRecv;
671cc290419Sopenharmony_ci    iov = uv_buf_init(reinterpret_cast<char *>(ctxRecv.buf), ctxRecv.bufSize);
672cc290419Sopenharmony_ci    ret = uv_fs_read(&daemon->loopMain, req, hUSB->bulkOut, &iov, 1, -1, OnUSBRead);
673cc290419Sopenharmony_ci    if (ret < 0) {
674cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "uv_fs_read ret:%d < 0", ret);
675cc290419Sopenharmony_ci        return ERR_API_FAIL;
676cc290419Sopenharmony_ci    }
677cc290419Sopenharmony_ci    ctxRecv.atPollQueue = true;
678cc290419Sopenharmony_ci    return RET_SUCCESS;
679cc290419Sopenharmony_ci}
680cc290419Sopenharmony_ci
681cc290419Sopenharmony_ci// Because USB can connect to only one host,daemonUSB is only one Session by default
682cc290419Sopenharmony_civoid HdcDaemonUSB::WatchEPTimer(uv_timer_t *handle)
683cc290419Sopenharmony_ci{
684cc290419Sopenharmony_ci    HdcDaemonUSB *thisClass = (HdcDaemonUSB *)handle->data;
685cc290419Sopenharmony_ci    HUSB hUSB = &thisClass->usbHandle;
686cc290419Sopenharmony_ci    HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(thisClass->clsMainBase);
687cc290419Sopenharmony_ci    if (thisClass->isAlive || thisClass->ctxRecv.atPollQueue) {
688cc290419Sopenharmony_ci        return;
689cc290419Sopenharmony_ci    }
690cc290419Sopenharmony_ci    bool resetEp = false;
691cc290419Sopenharmony_ci    do {
692cc290419Sopenharmony_ci        if (hUSB->bulkIn > 0) {
693cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "Watchdog close bulkin");
694cc290419Sopenharmony_ci            thisClass->CloseBulkEp(true, thisClass->usbHandle.bulkIn, &daemon->loopMain);
695cc290419Sopenharmony_ci            resetEp = true;
696cc290419Sopenharmony_ci        }
697cc290419Sopenharmony_ci        if (hUSB->bulkOut > 0) {
698cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "Watchdog close bulkout");
699cc290419Sopenharmony_ci            thisClass->CloseBulkEp(false, thisClass->usbHandle.bulkOut, &daemon->loopMain);
700cc290419Sopenharmony_ci            resetEp = true;
701cc290419Sopenharmony_ci        }
702cc290419Sopenharmony_ci        if (thisClass->controlEp > 0) {
703cc290419Sopenharmony_ci            Base::CloseFd(thisClass->controlEp);
704cc290419Sopenharmony_ci            resetEp = true;
705cc290419Sopenharmony_ci        }
706cc290419Sopenharmony_ci    } while (false);
707cc290419Sopenharmony_ci    if (resetEp || thisClass->usbHandle.bulkIn != 0 || thisClass->usbHandle.bulkOut != 0) {
708cc290419Sopenharmony_ci        return;
709cc290419Sopenharmony_ci    }
710cc290419Sopenharmony_ci    // until all bulkport reset
711cc290419Sopenharmony_ci    if (thisClass->ConnectEPPoint(hUSB) != RET_SUCCESS) {
712cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "WatchEPTimer ConnectEPPoint failed");
713cc290419Sopenharmony_ci        return;
714cc290419Sopenharmony_ci    }
715cc290419Sopenharmony_ci    // connect OK
716cc290419Sopenharmony_ci    thisClass->isAlive = true;
717cc290419Sopenharmony_ci    thisClass->LoopUSBRead(hUSB, hUSB->wMaxPacketSizeSend);
718cc290419Sopenharmony_ci}
719cc290419Sopenharmony_ci}  // namespace Hdc
720