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