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