• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "daemon_usb.h"
16 #include "usb_ffs.h"
17 
18 namespace Hdc {
HdcDaemonUSB(const bool serverOrDaemonIn,void * ptrMainBase)19 HdcDaemonUSB::HdcDaemonUSB(const bool serverOrDaemonIn, void *ptrMainBase)
20     : HdcUSBBase(serverOrDaemonIn, ptrMainBase)
21 {
22 }
23 
~HdcDaemonUSB()24 HdcDaemonUSB::~HdcDaemonUSB()
25 {
26     // Closed in the IO loop, no longer closing CLOSE ENDPOINT
27     if (controlEp > 0) {
28         close(controlEp);
29     }
30     if (ctxRecv.buf) {
31         delete[] ctxRecv.buf;
32     }
33     uv_fs_req_cleanup(&ctxRecv.req);
34 }
35 
Stop()36 void HdcDaemonUSB::Stop()
37 {
38     WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop");
39     // Here only clean up the IO-related resources, session related resources clear reason to clean up the session
40     // module
41     modRunning = false;
42     WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop free main session");
43     Base::TryCloseHandle((uv_handle_t *)&checkEP);
44     CloseEndpoint(&usbHandle);
45     WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop free main session finish");
46 }
47 
GetDevPath(const std::string & path)48 string HdcDaemonUSB::GetDevPath(const std::string &path)
49 {
50     DIR *dir = ::opendir(path.c_str());
51     if (dir == nullptr) {
52         WRITE_LOG(LOG_WARN, "%s: cannot open devpath: errno: %d", path.c_str(), errno);
53         return "";
54     }
55 
56     string res = USB_FFS_BASE;
57     string node;
58     int count = 0;
59     struct dirent *entry = nullptr;
60     while ((entry = ::readdir(dir))) {
61         if (*entry->d_name == '.') {
62             continue;
63         }
64         node = entry->d_name;
65         ++count;
66     }
67     if (count > 1) {
68         res += "hdc";
69     } else {
70         res += node;
71     }
72     ::closedir(dir);
73     return res;
74 }
75 
GetMaxPacketSize(int fdFfs)76 int HdcDaemonUSB::GetMaxPacketSize(int fdFfs)
77 {
78     // no ioctl support, todo dynamic get
79     return MAX_PACKET_SIZE_HISPEED;
80 }
81 
Initial()82 int HdcDaemonUSB::Initial()
83 {
84     // after Linux-3.8,kernel switch to the USB Function FS
85     // Implement USB hdc function in user space
86     WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB init");
87     basePath = GetDevPath(USB_FFS_BASE);
88     if (access((basePath + "/ep0").c_str(), F_OK) != 0) {
89         WRITE_LOG(LOG_DEBUG, "Only support usb-ffs, make sure kernel3.8+ and usb-ffs enabled, usbmode disabled");
90         return ERR_API_FAIL;
91     }
92     ctxRecv.thisClass = this;
93     ctxRecv.bufSizeMax = Base::GetUsbffsBulkSize();
94     ctxRecv.buf = new uint8_t[ctxRecv.bufSizeMax]();
95     if (!ctxRecv.buf) {
96         WRITE_LOG(LOG_FATAL, "Init alloc memory failed");
97         return ERR_BUF_ALLOC;
98     }
99 
100     HdcDaemon *daemon = (HdcDaemon *)clsMainBase;
101     WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB::Initiall");
102     uv_timer_init(&daemon->loopMain, &checkEP);
103     checkEP.data = this;
104     uv_timer_start(&checkEP, WatchEPTimer, 0, TIME_BASE);
105     return 0;
106 }
107 
108 // make gnuc++ happy. Clang support direct assignment value to structure, buf g++ weakness
FillUsbV2Head(usb_functionfs_desc_v2 & descUsbFfs)109 void HdcDaemonUSB::FillUsbV2Head(usb_functionfs_desc_v2 &descUsbFfs)
110 {
111     descUsbFfs.head.magic = LONG_LE(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
112     descUsbFfs.head.length = LONG_LE(sizeof(descUsbFfs));
113     descUsbFfs.head.flags
114         = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC | FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
115     descUsbFfs.config1Count = 3;
116     descUsbFfs.config2Count = 3;
117     descUsbFfs.config3Count = 5;
118     descUsbFfs.configWosCount = 1;
119     descUsbFfs.config1Desc = config1;
120     descUsbFfs.config2Desc = config2;
121     descUsbFfs.config3Desc = config3;
122     descUsbFfs.wosHead.interface = 1;
123     descUsbFfs.wosHead.dwLength = LONG_LE(sizeof(descUsbFfs.wosHead) + sizeof(descUsbFfs.wosDesc));
124     descUsbFfs.wosHead.bcdVersion = SHORT_LE(1);
125     descUsbFfs.wosHead.wIndex = SHORT_LE(4);
126     descUsbFfs.wosHead.bCount = 1;
127     descUsbFfs.wosHead.Reserved = 0;
128     descUsbFfs.wosDesc.bFirstInterfaceNumber = 0;
129     descUsbFfs.wosDesc.Reserved1 = 1;
130     descUsbFfs.wosDesc.CompatibleID[0] = 'W';
131     descUsbFfs.wosDesc.CompatibleID[1] = 'I';
132     descUsbFfs.wosDesc.CompatibleID[2] = 'N';
133     descUsbFfs.wosDesc.CompatibleID[3] = 'U';
134     descUsbFfs.wosDesc.CompatibleID[4] = 'S';
135     descUsbFfs.wosDesc.CompatibleID[5] = 'B';
136     descUsbFfs.wosDesc.CompatibleID[6] = '\0';
137     Base::ZeroArray(descUsbFfs.wosDesc.SubCompatibleID);
138     Base::ZeroArray(descUsbFfs.wosDesc.Reserved2);
139 }
140 
141 // DAEMON end USB module USB-FFS EP port connection
ConnectEPPoint(HUSB hUSB)142 int HdcDaemonUSB::ConnectEPPoint(HUSB hUSB)
143 {
144     int ret = ERR_GENERIC;
145     struct usb_functionfs_desc_v2 descUsbFfs = {};
146     FillUsbV2Head(descUsbFfs);
147     while (true) {
148         if (controlEp <= 0) {
149             // After the control port sends the instruction, the device is initialized by the device to the HOST host,
150             // which can be found for USB devices. Do not send initialization to the EP0 control port, the USB
151             // device will not be initialized by Host
152             WRITE_LOG(LOG_DEBUG, "Begin send to control(EP0) for usb descriptor init");
153             string ep0Path = basePath + "/ep0";
154             if ((controlEp = open(ep0Path.c_str(), O_RDWR)) < 0) {
155                 WRITE_LOG(LOG_WARN, "%s: cannot open control endpoint: errno=%d", ep0Path.c_str(), errno);
156                 break;
157             }
158             if (write(controlEp, &descUsbFfs, sizeof(descUsbFfs)) < 0) {
159                 WRITE_LOG(LOG_WARN, "%s: write ffs configs failed: errno=%d", ep0Path.c_str(), errno);
160                 break;
161             }
162             if (write(controlEp, &USB_FFS_VALUE, sizeof(USB_FFS_VALUE)) < 0) {
163                 WRITE_LOG(LOG_WARN, "%s: write USB_FFS_VALUE failed: errno=%d", ep0Path.c_str(), errno);
164                 break;
165             }
166             // active usbrc,Send USB initialization singal
167             SystemDepend::SetDevItem("sys.usb.ffs.ready", "1");
168             WRITE_LOG(LOG_DEBUG, "ConnectEPPoint ctrl init finish, set usb-ffs ready");
169         }
170         string outPath = basePath + "/ep1";
171         if ((hUSB->bulkOut = open(outPath.c_str(), O_RDWR)) < 0) {
172             WRITE_LOG(LOG_WARN, "%s: cannot open bulk-out ep: errno=%d", outPath.c_str(), errno);
173             break;
174         }
175         string inPath = basePath + "/ep2";
176         if ((hUSB->bulkIn = open(inPath.c_str(), O_RDWR)) < 0) {
177             WRITE_LOG(LOG_WARN, "%s: cannot open bulk-in ep: errno=%d", inPath.c_str(), errno);
178             break;
179         }
180         // cannot open with O_CLOEXEC, must fcntl
181         fcntl(controlEp, F_SETFD, FD_CLOEXEC);
182         fcntl(hUSB->bulkOut, F_SETFD, FD_CLOEXEC);
183         fcntl(hUSB->bulkIn, F_SETFD, FD_CLOEXEC);
184         hUSB->wMaxPacketSizeSend = GetMaxPacketSize(hUSB->bulkIn);
185 
186         WRITE_LOG(LOG_DEBUG, "New bulk in\\out open bulkout:%d bulkin:%d", hUSB->bulkOut, hUSB->bulkIn);
187         ret = RET_SUCCESS;
188         break;
189     }
190     if (ret != RET_SUCCESS) {
191         CloseEndpoint(hUSB, true);
192     }
193     return ret;
194 }
195 
CloseEndpoint(HUSB hUSB,bool closeCtrlEp)196 void HdcDaemonUSB::CloseEndpoint(HUSB hUSB, bool closeCtrlEp)
197 {
198     if (hUSB->bulkIn > 0) {
199         close(hUSB->bulkIn);
200         hUSB->bulkIn = 0;
201     }
202     if (hUSB->bulkOut > 0) {
203         close(hUSB->bulkOut);
204         hUSB->bulkOut = 0;
205     }
206     if (controlEp > 0 && closeCtrlEp) {
207         close(controlEp);
208         controlEp = 0;
209     }
210     isAlive = false;
211     WRITE_LOG(LOG_FATAL, "DaemonUSB close endpoint");
212 }
213 
ResetOldSession(uint32_t sessionId)214 void HdcDaemonUSB::ResetOldSession(uint32_t sessionId)
215 {
216     HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
217     if (sessionId == 0) {
218         sessionId = currentSessionId;
219     }
220     HSession hSession = daemon->AdminSession(OP_QUERY, sessionId, nullptr);
221     if (hSession == nullptr) {
222         return;
223     }
224     // The Host side is restarted, but the USB cable is still connected
225     WRITE_LOG(LOG_WARN, "Hostside softreset to restart daemon, old sessionId:%u", sessionId);
226     daemon->FreeSession(sessionId);
227 }
228 
229 // Prevent other USB data misfortunes to send the program crash
AvailablePacket(uint8_t * ioBuf,int ioBytes,uint32_t * sessionId)230 int HdcDaemonUSB::AvailablePacket(uint8_t *ioBuf, int ioBytes, uint32_t *sessionId)
231 {
232     int ret = RET_SUCCESS;
233     while (true) {
234         if (!IsUsbPacketHeader(ioBuf, ioBytes)) {
235             break;
236         }
237         // usb header
238         USBHead *usbPayloadHeader = (struct USBHead *)ioBuf;
239         uint32_t inSessionId = ntohl(usbPayloadHeader->sessionId);
240         if ((usbPayloadHeader->option & USB_OPTION_RESET)) {
241             ResetOldSession(inSessionId);
242             ret = ERR_IO_SOFT_RESET;
243             break;
244         }
245         *sessionId = inSessionId;
246         break;
247     }
248     return ret;
249 }
250 
251 // Work in subcrete,Work thread is ready
ReadyForWorkThread(HSession hSession)252 bool HdcDaemonUSB::ReadyForWorkThread(HSession hSession)
253 {
254     HdcUSBBase::ReadyForWorkThread(hSession);
255     return true;
256 };
257 
CloseBulkEp(bool bulkInOut,int bulkFd,uv_loop_t * loop)258 int HdcDaemonUSB::CloseBulkEp(bool bulkInOut, int bulkFd, uv_loop_t *loop)
259 {
260     struct CtxCloseBulkEp {
261         uv_fs_t req;
262         HdcDaemonUSB *thisClass;
263         bool bulkInOut;
264     };
265     CtxCloseBulkEp *ctx = new(std::nothrow) CtxCloseBulkEp();
266     if (ctx == nullptr) {
267         WRITE_LOG(LOG_FATAL, "CloseBulkEp new ctx failed");
268         return -1;
269     }
270     uv_fs_t *req = &ctx->req;
271     req->data = ctx;
272     ctx->bulkInOut = bulkInOut;
273     ctx->thisClass = this;
274     isAlive = false;
275     uv_fs_close(loop, req, bulkFd, [](uv_fs_t *req) {
276         auto ctx = (CtxCloseBulkEp *)req->data;
277         WRITE_LOG(LOG_DEBUG, "Try to abort blukin write callback %s", ctx->bulkInOut ? "bulkin" : "bulkout");
278         if (ctx->bulkInOut) {
279             ctx->thisClass->usbHandle.bulkIn = 0;
280         } else {
281             ctx->thisClass->usbHandle.bulkOut = 0;
282         }
283         uv_fs_req_cleanup(req);
284         delete ctx;
285     });
286     return 0;
287 }
288 
SendUSBIOSync(HSession hSession,HUSB hMainUSB,const uint8_t * data,const int length)289 int HdcDaemonUSB::SendUSBIOSync(HSession hSession, HUSB hMainUSB, const uint8_t *data, const int length)
290 {
291     int bulkIn = hMainUSB->bulkIn;
292     int childRet = 0;
293     int ret = ERR_IO_FAIL;
294     int offset = 0;
295     while (modRunning && isAlive && !hSession->isDead) {
296         childRet = write(bulkIn, (uint8_t *)data + offset, length - offset);
297         if (childRet <= 0) {
298             int err = errno;
299             if (err == EINTR) {
300                 WRITE_LOG(LOG_DEBUG, "BulkinWrite write EINTR, try again, offset:%u", offset);
301                 continue;
302             } else {
303                 WRITE_LOG(LOG_FATAL, "BulkinWrite write fatal errno %d", err);
304                 isAlive = false;
305             }
306             break;
307         }
308         offset += childRet;
309         if (offset >= length) {
310             break;
311         }
312     }
313     if (offset == length) {
314         ret = length;
315     } else {
316         WRITE_LOG(LOG_FATAL, "BulkinWrite write failed, nsize:%d really:%d modRunning:%d isAlive:%d SessionDead:%d",
317                   length, offset, modRunning, isAlive, hSession->isDead);
318     }
319     return ret;
320 }
321 
SendUSBRaw(HSession hSession,uint8_t * data,const int length)322 int HdcDaemonUSB::SendUSBRaw(HSession hSession, uint8_t *data, const int length)
323 {
324     HdcDaemon *daemon = (HdcDaemon *)hSession->classInstance;
325     std::unique_lock<std::mutex> lock(mutexUsbFfs);
326     ++hSession->ref;
327     int ret = SendUSBIOSync(hSession, &usbHandle, data, length);
328     --hSession->ref;
329     if (ret < 0) {
330         daemon->FreeSession(hSession->sessionId);
331         WRITE_LOG(LOG_DEBUG, "SendUSBRaw try to freesession");
332     }
333     return ret;
334 }
335 
336 // cross thread call
OnNewHandshakeOK(const uint32_t sessionId)337 void HdcDaemonUSB::OnNewHandshakeOK(const uint32_t sessionId)
338 {
339     currentSessionId = sessionId;  // sync with server, and set server's real Id
340 }
341 
342 // MainThreadCall, when seession was freeed
OnSessionFreeFinally(const HSession hSession)343 void HdcDaemonUSB::OnSessionFreeFinally(const HSession hSession)
344 {
345     if (currentSessionId == hSession->sessionId) {
346         isAlive = false;
347         // uv_cancel ctxRecv.req == UV_EBUSY, not effect immediately. It must be close by logic
348     }
349 }
350 
PrepareNewSession(uint32_t sessionId,uint8_t * pRecvBuf,int recvBytesIO)351 HSession HdcDaemonUSB::PrepareNewSession(uint32_t sessionId, uint8_t *pRecvBuf, int recvBytesIO)
352 {
353     HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
354     HSession hChildSession = daemon->MallocSession(false, CONN_USB, this, sessionId);
355     if (!hChildSession) {
356         return nullptr;
357     }
358     currentSessionId = sessionId;
359     Base::StartWorkThread(&daemon->loopMain, daemon->SessionWorkThread, Base::FinishWorkThread, hChildSession);
360     auto funcNewSessionUp = [](uv_timer_t *handle) -> void {
361         HSession hChildSession = reinterpret_cast<HSession>(handle->data);
362         HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(hChildSession->classInstance);
363         if (hChildSession->childLoop.active_handles == 0) {
364             return;
365         }
366         if (!hChildSession->isDead) {
367             auto ctrl = daemon->BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
368             Base::SendToStream((uv_stream_t *)&hChildSession->ctrlPipe[STREAM_MAIN], ctrl.data(), ctrl.size());
369             WRITE_LOG(LOG_DEBUG, "Main thread usbio mirgate finish");
370         }
371         Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(handle), Base::CloseTimerCallback);
372     };
373     Base::TimerUvTask(&daemon->loopMain, hChildSession, funcNewSessionUp);
374     return hChildSession;
375 }
376 
UsbToHdcProtocol(uv_stream_t * stream,uint8_t * appendData,int dataSize)377 int HdcDaemonUSB::UsbToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize)
378 {
379     return Base::SendToStream(stream, appendData, dataSize);
380 }
381 
DispatchToWorkThread(uint32_t sessionId,uint8_t * readBuf,int readBytes)382 int HdcDaemonUSB::DispatchToWorkThread(uint32_t sessionId, uint8_t *readBuf, int readBytes)
383 {
384     HSession hChildSession = nullptr;
385     HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
386     int childRet = RET_SUCCESS;
387     if (sessionId == 0) {
388         // hdc packet data
389         sessionId = currentSessionId;
390     }
391     if (currentSessionId != 0 && sessionId != currentSessionId) {
392         WRITE_LOG(LOG_WARN, "New session coming, restart old sessionId:%u", currentSessionId);
393         ResetOldSession(currentSessionId);
394         currentSessionId = 0;
395     }
396     hChildSession = daemon->AdminSession(OP_QUERY, sessionId, nullptr);
397     if (!hChildSession) {
398         hChildSession = PrepareNewSession(sessionId, readBuf, readBytes);
399         if (!hChildSession) {
400             WRITE_LOG(LOG_WARN, "prep new session err for sessionId:%u", sessionId);
401             return ERR_SESSION_NOFOUND;
402         }
403     }
404 
405     if (hChildSession->childCleared || hChildSession->isDead) {
406         WRITE_LOG(LOG_WARN, "session dead clr:%d - %d", hChildSession->childCleared, hChildSession->isDead);
407         return ERR_SESSION_DEAD;
408     }
409     uv_stream_t *stream = reinterpret_cast<uv_stream_t *>(&hChildSession->dataPipe[STREAM_MAIN]);
410     if ((childRet = SendToHdcStream(hChildSession, stream, readBuf, readBytes)) < 0) {
411         WRITE_LOG(LOG_WARN, "DispatchToWorkThread SendToHdcStream err ret:%d", childRet);
412         return ERR_IO_FAIL;
413     }
414     return childRet;
415 }
416 
JumpAntiquePacket(const uint8_t & buf,ssize_t bytes) const417 bool HdcDaemonUSB::JumpAntiquePacket(const uint8_t &buf, ssize_t bytes) const
418 {
419     constexpr size_t antiqueFlagSize = 4;
420     constexpr size_t antiqueFullSize = 24;
421     // anti CNXN 0x4e584e43
422     uint8_t flag[] = { 0x43, 0x4e, 0x58, 0x4e };
423     if (bytes == antiqueFullSize && !memcmp(&buf, flag, antiqueFlagSize)) {
424         return true;
425     }
426     return false;
427 }
428 
429 // Only physically swap EP ports will be reset
OnUSBRead(uv_fs_t * req)430 void HdcDaemonUSB::OnUSBRead(uv_fs_t *req)
431 {  // Only read at the main thread
432     auto ctxIo = reinterpret_cast<CtxUvFileCommonIo *>(req->data);
433     auto hUSB = reinterpret_cast<HUSB>(ctxIo->data);
434     auto thisClass = reinterpret_cast<HdcDaemonUSB *>(ctxIo->thisClass);
435     uint8_t *bufPtr = ctxIo->buf;
436     ssize_t bytesIOBytes = req->result;
437     uint32_t sessionId = 0;
438     bool ret = false;
439     int childRet = 0;
440     if (bytesIOBytes > hUSB->wMaxPacketSizeSend && bytesIOBytes != thisClass->saveNextReadSize) {
441         WRITE_LOG(LOG_WARN, "Not full packet, wanted:%d really:%d", thisClass->saveNextReadSize, bytesIOBytes);
442     }
443     while (thisClass->isAlive) {
444         // Don't care is module running, first deal with this
445         if (bytesIOBytes < 0) {
446             // logic alive and EINTER is gdb attach
447             //
448             // [about gdb attach known issue]
449             // When GDB debugging is loaded, the number of USB read interrupts of libuv will increase. Multiple
450             // interrupts will increase the correctness of USB data reading. Setting GDB to asynchronous mode or using
451             // log debugging can avoid this problem
452             if (bytesIOBytes != -EINTR) {  // Epoll will be broken when gdb attach
453                 constexpr int bufSize = 1024;
454                 char buf[bufSize] = { 0 };
455                 uv_strerror_r(bytesIOBytes, buf, bufSize);
456                 WRITE_LOG(LOG_WARN, "USBIO ret:%d failed:%s", bytesIOBytes, buf);
457                 ret = false;
458                 break;
459             } else {
460                 WRITE_LOG(LOG_ALL, "OnUSBRead signal EINTR");
461             }
462         } else if (bytesIOBytes == 0) {  // zero packet
463             WRITE_LOG(LOG_ALL, "Zero packet received");
464         } else {
465             if (thisClass->JumpAntiquePacket(*bufPtr, bytesIOBytes)) {
466                 WRITE_LOG(LOG_DEBUG, "JumpAntiquePacket auto jump");
467                 ret = true;
468                 break;
469             }
470             // guess is head of packet
471             if ((childRet = thisClass->AvailablePacket((uint8_t *)bufPtr, bytesIOBytes, &sessionId)) != RET_SUCCESS) {
472                 if (childRet != ERR_IO_SOFT_RESET) {
473                     WRITE_LOG(LOG_WARN, "AvailablePacket check failed, ret:%d buf:%-50s", bytesIOBytes, bufPtr);
474                     break;
475                 }
476                 // reset packet
477                 childRet = 0;  // need max size
478             } else {
479                 // AvailablePacket case
480                 if ((childRet = thisClass->DispatchToWorkThread(sessionId, bufPtr, bytesIOBytes)) < 0) {
481                     WRITE_LOG(LOG_FATAL, "DispatchToWorkThread failed");
482                     break;
483                 }
484             }
485         }
486         int nextReadSize = childRet == 0 ? hUSB->wMaxPacketSizeSend : std::min(childRet, Base::GetUsbffsBulkSize());
487         thisClass->saveNextReadSize = nextReadSize;
488         if (thisClass->LoopUSBRead(hUSB, nextReadSize) < 0) {
489             WRITE_LOG(LOG_FATAL, "LoopUSBRead failed");
490             break;
491         }
492         ret = true;
493         break;
494     }
495     if (!ret) {
496         thisClass->isAlive = false;
497         thisClass->ctxRecv.atPollQueue = false;
498     }
499 }
500 
LoopUSBRead(HUSB hUSB,int readMaxWanted)501 int HdcDaemonUSB::LoopUSBRead(HUSB hUSB, int readMaxWanted)
502 {
503     int ret = ERR_GENERIC;
504     HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
505     uv_buf_t iov;
506     ctxRecv.data = hUSB;
507     ctxRecv.bufSize = readMaxWanted;
508     ctxRecv.req = {};
509     uv_fs_t *req = &ctxRecv.req;
510     req->data = &ctxRecv;
511     iov = uv_buf_init(reinterpret_cast<char *>(ctxRecv.buf), ctxRecv.bufSize);
512     ret = uv_fs_read(&daemon->loopMain, req, hUSB->bulkOut, &iov, 1, -1, OnUSBRead);
513     if (ret < 0) {
514         WRITE_LOG(LOG_FATAL, "uv_fs_read < 0");
515         return ERR_API_FAIL;
516     }
517     ctxRecv.atPollQueue = true;
518     return RET_SUCCESS;
519 }
520 
521 // Because USB can connect to only one host,daemonUSB is only one Session by default
WatchEPTimer(uv_timer_t * handle)522 void HdcDaemonUSB::WatchEPTimer(uv_timer_t *handle)
523 {
524     HdcDaemonUSB *thisClass = (HdcDaemonUSB *)handle->data;
525     HUSB hUSB = &thisClass->usbHandle;
526     HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(thisClass->clsMainBase);
527     if (thisClass->isAlive || thisClass->ctxRecv.atPollQueue) {
528         return;
529     }
530     bool resetEp = false;
531     do {
532         if (hUSB->bulkIn > 0) {
533             WRITE_LOG(LOG_DEBUG, "Watchdog close bulkin");
534             thisClass->CloseBulkEp(true, thisClass->usbHandle.bulkIn, &daemon->loopMain);
535             resetEp = true;
536         }
537         if (hUSB->bulkOut > 0) {
538             WRITE_LOG(LOG_DEBUG, "Watchdog close bulkout");
539             thisClass->CloseBulkEp(false, thisClass->usbHandle.bulkOut, &daemon->loopMain);
540             resetEp = true;
541         }
542         if (thisClass->controlEp > 0) {
543             close(thisClass->controlEp);
544             thisClass->controlEp = 0;
545             resetEp = true;
546         }
547     } while (false);
548     if (resetEp || thisClass->usbHandle.bulkIn != 0 || thisClass->usbHandle.bulkOut != 0) {
549         return;
550     }
551     // until all bulkport reset
552     if (thisClass->ConnectEPPoint(hUSB) != RET_SUCCESS) {
553         return;
554     }
555     // connect OK
556     thisClass->isAlive = true;
557     thisClass->LoopUSBRead(hUSB, hUSB->wMaxPacketSizeSend);
558 }
559 }  // namespace Hdc
560