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