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 "host_usb.h"
16 #include <stdlib.h>
17 #include <thread>
18
19 #include "server.h"
20 namespace Hdc {
HdcHostUSB(const bool serverOrDaemonIn,void * ptrMainBase,void * ctxUSBin)21 HdcHostUSB::HdcHostUSB(const bool serverOrDaemonIn, void *ptrMainBase, void *ctxUSBin)
22 : HdcUSBBase(serverOrDaemonIn, ptrMainBase)
23 {
24 modRunning = false;
25 HdcServer *pServer = (HdcServer *)ptrMainBase;
26 ctxUSB = (libusb_context *)ctxUSBin;
27 uv_timer_init(&pServer->loopMain, &devListWatcher);
28 }
29
~HdcHostUSB()30 HdcHostUSB::~HdcHostUSB()
31 {
32 if (modRunning) {
33 Stop();
34 }
35 WRITE_LOG(LOG_DEBUG, "~HdcHostUSB");
36 }
37
Stop()38 void HdcHostUSB::Stop()
39 {
40 if (!ctxUSB) {
41 return;
42 }
43 Base::TryCloseHandle((uv_handle_t *)&devListWatcher);
44 modRunning = false;
45 }
46
Initial()47 int HdcHostUSB::Initial()
48 {
49 if (!ctxUSB) {
50 WRITE_LOG(LOG_FATAL, "USB mod ctxUSB is nullptr, recompile please");
51 return -1;
52 }
53 WRITE_LOG(LOG_DEBUG, "HdcHostUSB init");
54 modRunning = true;
55 StartupUSBWork(); // Main thread registration, IO in sub-thread
56 return 0;
57 }
58
UsbLogHandler(libusb_context * ctx,enum libusb_log_level level,const char * str)59 static void UsbLogHandler(libusb_context* ctx, enum libusb_log_level level, const char* str)
60 {
61 int l = -1;
62 switch (level) {
63 case LIBUSB_LOG_LEVEL_ERROR:
64 l = LOG_FATAL;
65 break;
66 case LIBUSB_LOG_LEVEL_WARNING:
67 l = LOG_WARN;
68 break;
69 case LIBUSB_LOG_LEVEL_INFO:
70 l = LOG_INFO;
71 break;
72 case LIBUSB_LOG_LEVEL_DEBUG:
73 l = LOG_DEBUG;
74 break;
75 default:
76 break;
77 }
78 if (l >= 0) {
79 char *newStr = strdup(str);
80 if (!newStr) {
81 return;
82 }
83 char *p = strstr(newStr, "libusb:");
84 if (!p) {
85 p = newStr;
86 }
87 char *q = strrchr(newStr, '\n');
88 if (q) {
89 *q = '\0';
90 }
91 WRITE_LOG(l, "%s", p);
92 free(newStr);
93 }
94 }
InitLogging(void * ctxUSB)95 void HdcHostUSB::InitLogging(void *ctxUSB)
96 {
97 std::string debugEnv = "LIBUSB_DEBUG";
98 libusb_log_level debugLevel;
99
100 switch (static_cast<Hdc::LogLevel>(Base::GetLogLevel())) {
101 case LOG_WARN:
102 debugLevel = LIBUSB_LOG_LEVEL_ERROR;
103 break;
104 case LOG_INFO:
105 debugLevel = LIBUSB_LOG_LEVEL_WARNING;
106 break;
107 case LOG_DEBUG:
108 debugLevel = LIBUSB_LOG_LEVEL_INFO;
109 break;
110 case LOG_VERBOSE:
111 debugLevel = LIBUSB_LOG_LEVEL_DEBUG;
112 break;
113 case LOG_FATAL:
114 // pass through to no libusb logging
115 default:
116 debugLevel = LIBUSB_LOG_LEVEL_NONE;
117 break;
118 }
119
120 libusb_set_option((libusb_context *)ctxUSB, LIBUSB_OPTION_LOG_LEVEL, debugLevel);
121 libusb_set_log_cb((libusb_context *)ctxUSB, UsbLogHandler,
122 LIBUSB_LOG_CB_CONTEXT | LIBUSB_LOG_CB_GLOBAL);
123
124 #ifdef _WIN32
125 debugEnv += "=";
126 debugEnv += std::to_string(debugLevel);
127 _putenv(debugEnv.c_str());
128 #else
129 setenv(debugEnv.c_str(), std::to_string(debugLevel).c_str(), 1);
130 #endif
131 }
132
DetectMyNeed(libusb_device * device,string & sn)133 bool HdcHostUSB::DetectMyNeed(libusb_device *device, string &sn)
134 {
135 HUSB hUSB = new(std::nothrow) HdcUSB();
136 if (hUSB == nullptr) {
137 WRITE_LOG(LOG_FATAL, "DetectMyNeed new hUSB failed");
138 return false;
139 }
140 hUSB->device = device;
141 // just get usb SN, close handle immediately
142 int childRet = OpenDeviceMyNeed(hUSB);
143 if (childRet < 0) {
144 delete hUSB;
145 return false;
146 }
147 libusb_release_interface(hUSB->devHandle, hUSB->interfaceNumber);
148 libusb_close(hUSB->devHandle);
149 hUSB->devHandle = nullptr;
150
151 WRITE_LOG(LOG_INFO, "Needed device found, busid:%d devid:%d connectkey:%s", hUSB->busId, hUSB->devId,
152 hUSB->serialNumber.c_str());
153 // USB device is automatically connected after recognition, auto connect USB
154 UpdateUSBDaemonInfo(hUSB, nullptr, STATUS_READY);
155 HdcServer *hdcServer = (HdcServer *)clsMainBase;
156 HSession hSession = hdcServer->MallocSession(true, CONN_USB, this);
157 hSession->connectKey = hUSB->serialNumber;
158 uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
159 if (waitTimeDoCmd == nullptr) {
160 WRITE_LOG(LOG_FATAL, "DetectMyNeed new waitTimeDoCmd failed");
161 delete hUSB;
162 return false;
163 }
164 uv_timer_init(&hdcServer->loopMain, waitTimeDoCmd);
165 waitTimeDoCmd->data = hSession;
166 uv_timer_start(waitTimeDoCmd, hdcServer->UsbPreConnect, 0, DEVICE_CHECK_INTERVAL);
167 mapIgnoreDevice[sn] = HOST_USB_REGISTER;
168 delete hUSB;
169 return true;
170 }
171
KickoutZombie(HSession hSession)172 void HdcHostUSB::KickoutZombie(HSession hSession)
173 {
174 HdcServer *ptrConnect = (HdcServer *)hSession->classInstance;
175 HUSB hUSB = hSession->hUSB;
176 if (!hUSB->devHandle) {
177 WRITE_LOG(LOG_WARN, "KickoutZombie devHandle:%p isDead:%d", hUSB->devHandle, hSession->isDead);
178 return;
179 }
180 if (LIBUSB_ERROR_NO_DEVICE != libusb_kernel_driver_active(hUSB->devHandle, hUSB->interfaceNumber)) {
181 return;
182 }
183 WRITE_LOG(LOG_WARN, "KickoutZombie LIBUSB_ERROR_NO_DEVICE serialNumber:%s", hUSB->serialNumber.c_str());
184 ptrConnect->FreeSession(hSession->sessionId);
185 }
186
RemoveIgnoreDevice(string & mountInfo)187 void HdcHostUSB::RemoveIgnoreDevice(string &mountInfo)
188 {
189 if (mapIgnoreDevice.count(mountInfo)) {
190 mapIgnoreDevice.erase(mountInfo);
191 }
192 }
193
ReviewUsbNodeLater(string & nodeKey)194 void HdcHostUSB::ReviewUsbNodeLater(string &nodeKey)
195 {
196 HdcServer *hdcServer = (HdcServer *)clsMainBase;
197 // add to ignore list
198 mapIgnoreDevice[nodeKey] = HOST_USB_IGNORE;
199 int delayRemoveFromList = DEVICE_CHECK_INTERVAL * MINOR_TIMEOUT; // wait little time for daemon reinit
200 Base::DelayDo(&hdcServer->loopMain, delayRemoveFromList, 0, nodeKey, nullptr,
201 [this](const uint8_t flag, string &msg, const void *) -> void { RemoveIgnoreDevice(msg); });
202 }
203
WatchUsbNodeChange(uv_timer_t * handle)204 void HdcHostUSB::WatchUsbNodeChange(uv_timer_t *handle)
205 {
206 HdcHostUSB *thisClass = (HdcHostUSB *)handle->data;
207 HdcServer *ptrConnect = (HdcServer *)thisClass->clsMainBase;
208 libusb_device **devs = nullptr;
209 libusb_device *dev = nullptr;
210 // kick zombie
211 ptrConnect->EnumUSBDeviceRegister(KickoutZombie);
212 // find new
213 ssize_t cnt = libusb_get_device_list(thisClass->ctxUSB, &devs);
214 if (cnt < 0) {
215 WRITE_LOG(LOG_FATAL, "Failed to get device list");
216 return;
217 }
218 int i = 0;
219 // linux replug devid increment,windows will be not
220 while ((dev = devs[i++]) != nullptr) { // must postfix++
221 string szTmpKey = Base::StringFormat("%d-%d", libusb_get_bus_number(dev), libusb_get_device_address(dev));
222 // check is in ignore list
223 UsbCheckStatus statusCheck = thisClass->mapIgnoreDevice[szTmpKey];
224 if (statusCheck == HOST_USB_IGNORE || statusCheck == HOST_USB_REGISTER) {
225 continue;
226 }
227 string sn = szTmpKey;
228 if (!thisClass->DetectMyNeed(dev, sn)) {
229 thisClass->ReviewUsbNodeLater(szTmpKey);
230 }
231 }
232 libusb_free_device_list(devs, 1);
233 }
234
235 // Main thread USB operates in this thread
UsbWorkThread(void * arg)236 void HdcHostUSB::UsbWorkThread(void *arg)
237 {
238 HdcHostUSB *thisClass = (HdcHostUSB *)arg;
239 constexpr uint8_t usbHandleTimeout = 30; // second
240 while (thisClass->modRunning) {
241 struct timeval zerotime;
242 zerotime.tv_sec = usbHandleTimeout;
243 zerotime.tv_usec = 0; // if == 0,windows will be high CPU load
244 libusb_handle_events_timeout(thisClass->ctxUSB, &zerotime);
245 }
246 WRITE_LOG(LOG_DEBUG, "Host Sessionbase usb workthread finish");
247 }
248
StartupUSBWork()249 int HdcHostUSB::StartupUSBWork()
250 {
251 // Because libusb(winusb backend) does not support hotplug under win32, we use list mode for all platforms
252 WRITE_LOG(LOG_DEBUG, "USBHost loopfind mode");
253 devListWatcher.data = this;
254 uv_timer_start(&devListWatcher, WatchUsbNodeChange, 0, DEVICE_CHECK_INTERVAL);
255 // Running pendding in independent threads does not significantly improve the efficiency
256 uv_thread_create(&threadUsbWork, UsbWorkThread, this);
257 return 0;
258 }
259
CheckDescriptor(HUSB hUSB,libusb_device_descriptor & desc)260 int HdcHostUSB::CheckDescriptor(HUSB hUSB, libusb_device_descriptor& desc)
261 {
262 char serialNum[BUF_SIZE_MEDIUM] = "";
263 int childRet = 0;
264 uint8_t curBus = libusb_get_bus_number(hUSB->device);
265 uint8_t curDev = libusb_get_device_address(hUSB->device);
266 hUSB->busId = curBus;
267 hUSB->devId = curDev;
268 if (libusb_get_device_descriptor(hUSB->device, &desc)) {
269 WRITE_LOG(LOG_WARN, "CheckDescriptor libusb_get_device_descriptor failed %d-%d", curBus, curDev);
270 return -1;
271 }
272 // Get the serial number of the device, if there is no serial number, use the ID number to replace
273 // If the device is not in time, occasionally can't get it, this is determined by the external factor, cannot be
274 // changed. LIBUSB_SUCCESS
275 childRet = libusb_get_string_descriptor_ascii(hUSB->devHandle, desc.iSerialNumber, (uint8_t *)serialNum,
276 sizeof(serialNum));
277 if (childRet < 0) {
278 WRITE_LOG(LOG_WARN, "CheckDescriptor libusb_get_string_descriptor_ascii failed %d-%d", curBus, curDev);
279 return -1;
280 } else {
281 hUSB->serialNumber = serialNum;
282 }
283 WRITE_LOG(LOG_DEBUG, "CheckDescriptor busId-devId:%d-%d serialNum:%s", curBus, curDev, serialNum);
284 return 0;
285 }
286
287 // hSession can be null
UpdateUSBDaemonInfo(HUSB hUSB,HSession hSession,uint8_t connStatus)288 void HdcHostUSB::UpdateUSBDaemonInfo(HUSB hUSB, HSession hSession, uint8_t connStatus)
289 {
290 // add to list
291 HdcServer *pServer = (HdcServer *)clsMainBase;
292 HdcDaemonInformation di;
293 di.connectKey = hUSB->serialNumber;
294 di.connType = CONN_USB;
295 di.connStatus = connStatus;
296 di.hSession = hSession;
297 di.usbMountPoint = "";
298 di.usbMountPoint = Base::StringFormat("%d-%d", hUSB->busId, hUSB->devId);
299
300 HDaemonInfo pDi = nullptr;
301 HDaemonInfo hdiNew = &di;
302 pServer->AdminDaemonMap(OP_QUERY, hUSB->serialNumber, pDi);
303 if (!pDi) {
304 pServer->AdminDaemonMap(OP_ADD, hUSB->serialNumber, hdiNew);
305 } else {
306 pServer->AdminDaemonMap(OP_UPDATE, hUSB->serialNumber, hdiNew);
307 }
308 }
309
IsDebuggableDev(const struct libusb_interface_descriptor * ifDescriptor)310 bool HdcHostUSB::IsDebuggableDev(const struct libusb_interface_descriptor *ifDescriptor)
311 {
312 constexpr uint8_t harmonyEpNum = 2;
313 constexpr uint8_t harmonyClass = 0xff;
314 constexpr uint8_t harmonySubClass = 0x50;
315 constexpr uint8_t harmonyProtocol = 0x01;
316
317 if (ifDescriptor->bInterfaceClass != harmonyClass || ifDescriptor->bInterfaceSubClass != harmonySubClass ||
318 ifDescriptor->bInterfaceProtocol != harmonyProtocol) {
319 return false;
320 }
321 if (ifDescriptor->bNumEndpoints != harmonyEpNum) {
322 return false;
323 }
324 return true;
325 }
326
CheckActiveConfig(libusb_device * device,HUSB hUSB,libusb_device_descriptor & desc)327 int HdcHostUSB::CheckActiveConfig(libusb_device *device, HUSB hUSB, libusb_device_descriptor& desc)
328 {
329 unsigned int j = 0;
330 struct libusb_config_descriptor *descConfig = nullptr;
331 int ret = libusb_get_active_config_descriptor(device, &descConfig);
332 if (ret != 0)
333 {
334 #ifdef HOST_MAC
335 if ((desc.bDeviceClass == 0xFF)
336 && (desc.bDeviceSubClass == 0xFF)
337 && (desc.bDeviceProtocol == 0xFF))
338 {
339 ret = libusb_set_configuration(hUSB->devHandle, 1);
340 if (ret != 0)
341 {
342 WRITE_LOG(LOG_WARN, "set config failed ret:%d", ret);
343 return -1;
344 }
345 }
346
347 ret = libusb_get_active_config_descriptor(device, &descConfig);
348 if (ret != 0)
349 {
350 #endif
351 return -1;
352 }
353 #ifdef HOST_MAC
354 }
355 #endif
356
357 ret = -1;
358 for (j = 0; j < descConfig->bNumInterfaces; ++j) {
359 const struct libusb_interface *interface = &descConfig->interface[j];
360 if (interface->num_altsetting >= 1) {
361 const struct libusb_interface_descriptor *ifDescriptor = &interface->altsetting[0];
362 if (!IsDebuggableDev(ifDescriptor)) {
363 continue;
364 }
365 WRITE_LOG(LOG_DEBUG, "CheckActiveConfig IsDebuggableDev passed and then check endpoint attr");
366 hUSB->interfaceNumber = ifDescriptor->bInterfaceNumber;
367 unsigned int k = 0;
368 for (k = 0; k < ifDescriptor->bNumEndpoints; ++k) {
369 const struct libusb_endpoint_descriptor *ep_desc = &ifDescriptor->endpoint[k];
370 if ((ep_desc->bmAttributes & 0x03) == LIBUSB_TRANSFER_TYPE_BULK) {
371 if (ep_desc->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
372 hUSB->hostBulkIn.endpoint = ep_desc->bEndpointAddress;
373 hUSB->hostBulkIn.bulkInOut = true;
374 } else {
375 hUSB->hostBulkOut.endpoint = ep_desc->bEndpointAddress;
376 hUSB->wMaxPacketSizeSend = ep_desc->wMaxPacketSize;
377 hUSB->hostBulkOut.bulkInOut = false;
378 }
379 }
380 }
381 if (hUSB->hostBulkIn.endpoint == 0 || hUSB->hostBulkOut.endpoint == 0) {
382 break;
383 }
384 ret = 0;
385 }
386 }
387 libusb_free_config_descriptor(descConfig);
388 return ret;
389 }
390
391 // multi-thread calll
CancelUsbIo(HSession hSession)392 void HdcHostUSB::CancelUsbIo(HSession hSession)
393 {
394 WRITE_LOG(LOG_DEBUG, "HostUSB CancelUsbIo, ref:%u", uint32_t(hSession->ref));
395 HUSB hUSB = hSession->hUSB;
396 std::unique_lock<std::mutex> lock(hUSB->lockDeviceHandle);
397 if (!hUSB->hostBulkIn.isShutdown) {
398 if (!hUSB->hostBulkIn.isComplete) {
399 libusb_cancel_transfer(hUSB->hostBulkIn.transfer);
400 hUSB->hostBulkIn.cv.notify_one();
401 } else {
402 hUSB->hostBulkIn.isShutdown = true;
403 }
404 }
405 if (!hUSB->hostBulkOut.isShutdown) {
406 if (!hUSB->hostBulkOut.isComplete) {
407 libusb_cancel_transfer(hUSB->hostBulkOut.transfer);
408 hUSB->hostBulkOut.cv.notify_one();
409 } else {
410 hUSB->hostBulkOut.isShutdown = true;
411 }
412 }
413 }
414
415 // 3rd write child-hdc-workthread
416 // no use uvwrite, raw write to socketpair's fd
UsbToHdcProtocol(uv_stream_t * stream,uint8_t * appendData,int dataSize)417 int HdcHostUSB::UsbToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize)
418 {
419 HSession hSession = (HSession)stream->data;
420 unsigned int fd = hSession->dataFd[STREAM_MAIN];
421 fd_set fdSet;
422 struct timeval timeout = { 3, 0 };
423 FD_ZERO(&fdSet);
424 FD_SET(fd, &fdSet);
425 int index = 0;
426 int childRet = 0;
427
428 while (index < dataSize) {
429 if ((childRet = select(fd + 1, nullptr, &fdSet, nullptr, &timeout)) <= 0) {
430 constexpr int bufSize = 1024;
431 char buf[bufSize] = { 0 };
432 #ifdef _WIN32
433 strerror_s(buf, bufSize, errno);
434 #else
435 strerror_r(errno, buf, bufSize);
436 #endif
437 WRITE_LOG(LOG_FATAL, "select error:%d [%s][%d]", errno, buf, childRet);
438 break;
439 }
440 childRet = send(fd, reinterpret_cast<const char *>(appendData) + index, dataSize - index, 0);
441 if (childRet < 0) {
442 constexpr int bufSize = 1024;
443 char buf[bufSize] = { 0 };
444 #ifdef _WIN32
445 strerror_s(buf, bufSize, errno);
446 #else
447 strerror_r(errno, buf, bufSize);
448 #endif
449 WRITE_LOG(LOG_FATAL, "UsbToHdcProtocol senddata err:%d [%s]", errno, buf);
450 break;
451 }
452 index += childRet;
453 }
454 if (index != dataSize) {
455 WRITE_LOG(LOG_FATAL, "UsbToHdcProtocol partialsenddata err:%d [%d]", index, dataSize);
456 return ERR_IO_FAIL;
457 }
458 return index;
459 }
460
USBBulkCallback(struct libusb_transfer * transfer)461 void LIBUSB_CALL HdcHostUSB::USBBulkCallback(struct libusb_transfer *transfer)
462 {
463 auto *ep = reinterpret_cast<HostUSBEndpoint *>(transfer->user_data);
464 std::unique_lock<std::mutex> lock(ep->mutexIo);
465 bool retrySumit = false;
466 int childRet = 0;
467 do {
468 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
469 WRITE_LOG(LOG_FATAL, "USBBulkCallback1 failed, ret:%d", transfer->status);
470 break;
471 }
472 if (!ep->bulkInOut && transfer->actual_length != transfer->length) {
473 transfer->length -= transfer->actual_length;
474 transfer->buffer += transfer->actual_length;
475 retrySumit = true;
476 break;
477 }
478 } while (false);
479 while (retrySumit) {
480 childRet = libusb_submit_transfer(transfer);
481 if (childRet != 0) {
482 WRITE_LOG(LOG_FATAL, "USBBulkCallback2 failed, ret:%d", childRet);
483 transfer->status = LIBUSB_TRANSFER_ERROR;
484 break;
485 }
486 return;
487 }
488 ep->isComplete = true;
489 ep->cv.notify_one();
490 }
491
SubmitUsbBio(HSession hSession,bool sendOrRecv,uint8_t * buf,int bufSize)492 int HdcHostUSB::SubmitUsbBio(HSession hSession, bool sendOrRecv, uint8_t *buf, int bufSize)
493 {
494 HUSB hUSB = hSession->hUSB;
495 int timeout = 0;
496 int childRet = 0;
497 int ret = ERR_IO_FAIL;
498 HostUSBEndpoint *ep = nullptr;
499
500 if (sendOrRecv) {
501 timeout = GLOBAL_TIMEOUT * TIME_BASE;
502 ep = &hUSB->hostBulkOut;
503 } else {
504 timeout = 0; // infinity
505 ep = &hUSB->hostBulkIn;
506 }
507 hUSB->lockDeviceHandle.lock();
508 ep->isComplete = false;
509 do {
510 std::unique_lock<std::mutex> lock(ep->mutexIo);
511 libusb_fill_bulk_transfer(ep->transfer, hUSB->devHandle, ep->endpoint, buf, bufSize, USBBulkCallback, ep,
512 timeout);
513 childRet = libusb_submit_transfer(ep->transfer);
514 hUSB->lockDeviceHandle.unlock();
515 if (childRet < 0) {
516 WRITE_LOG(LOG_FATAL, "SubmitUsbBio libusb_submit_transfer failed, ret:%d", childRet);
517 break;
518 }
519 ep->cv.wait(lock, [ep]() { return ep->isComplete; });
520 if (ep->transfer->status != 0) {
521 WRITE_LOG(LOG_FATAL, "SubmitUsbBio transfer failed, status:%d", ep->transfer->status);
522 break;
523 }
524 ret = ep->transfer->actual_length;
525 } while (false);
526 return ret;
527 }
528
BeginUsbRead(HSession hSession)529 void HdcHostUSB::BeginUsbRead(HSession hSession)
530 {
531 HUSB hUSB = hSession->hUSB;
532 hUSB->hostBulkIn.isShutdown = false;
533 hUSB->hostBulkOut.isShutdown = false;
534 ++hSession->ref;
535 // loop read
536 std::thread([this, hSession, hUSB]() {
537 int childRet = 0;
538 int nextReadSize = 0;
539 while (!hSession->isDead) {
540 // if readIO < wMaxPacketSizeSend, libusb report overflow
541 nextReadSize = (childRet < hUSB->wMaxPacketSizeSend ? hUSB->wMaxPacketSizeSend
542 : std::min(childRet, Base::GetUsbffsBulkSize()));
543 childRet = SubmitUsbBio(hSession, false, hUSB->hostBulkIn.buf, nextReadSize);
544 if (childRet < 0) {
545 WRITE_LOG(LOG_FATAL, "Read usb failed, ret:%d", childRet);
546 break;
547 }
548 childRet = SendToHdcStream(hSession, reinterpret_cast<uv_stream_t *>(&hSession->dataPipe[STREAM_MAIN]),
549 hUSB->hostBulkIn.buf, childRet);
550 if (childRet < 0) {
551 WRITE_LOG(LOG_FATAL, "SendToHdcStream failed, ret:%d", childRet);
552 break;
553 }
554 }
555 --hSession->ref;
556 auto server = reinterpret_cast<HdcServer *>(clsMainBase);
557 hUSB->hostBulkIn.isShutdown = true;
558 server->FreeSession(hSession->sessionId);
559 WRITE_LOG(LOG_DEBUG, "Usb loop read finish");
560 }).detach();
561 }
562
563 // ==0 Represents new equipment and is what we need,<0 my need
OpenDeviceMyNeed(HUSB hUSB)564 int HdcHostUSB::OpenDeviceMyNeed(HUSB hUSB)
565 {
566 libusb_device *device = hUSB->device;
567 int ret = -1;
568 if (LIBUSB_SUCCESS != libusb_open(device, &hUSB->devHandle)) {
569 return -100;
570 }
571 while (modRunning) {
572 libusb_device_handle *handle = hUSB->devHandle;
573 struct libusb_device_descriptor desc;
574 if (CheckDescriptor(hUSB, desc)) {
575 break;
576 }
577 if (CheckActiveConfig(device, hUSB, desc)) {
578 break;
579 }
580 // USB filter rules are set according to specific device pedding device
581 ret = libusb_claim_interface(handle, hUSB->interfaceNumber);
582 break;
583 }
584 if (ret) {
585 // not my need device, release the device
586 libusb_close(hUSB->devHandle);
587 hUSB->devHandle = nullptr;
588 }
589 return ret;
590 }
591
SendUSBRaw(HSession hSession,uint8_t * data,const int length)592 int HdcHostUSB::SendUSBRaw(HSession hSession, uint8_t *data, const int length)
593 {
594 int ret = ERR_GENERIC;
595 HdcSessionBase *server = reinterpret_cast<HdcSessionBase *>(hSession->classInstance);
596 ++hSession->ref;
597 ret = SubmitUsbBio(hSession, true, data, length);
598 if (ret < 0) {
599 WRITE_LOG(LOG_FATAL, "Send usb failed, ret:%d", ret);
600 CancelUsbIo(hSession);
601 hSession->hUSB->hostBulkOut.isShutdown = true;
602 server->FreeSession(hSession->sessionId);
603 }
604 --hSession->ref;
605 return ret;
606 }
607
FindDeviceByID(HUSB hUSB,const char * usbMountPoint,libusb_context * ctxUSB)608 bool HdcHostUSB::FindDeviceByID(HUSB hUSB, const char *usbMountPoint, libusb_context *ctxUSB)
609 {
610 libusb_device **listDevices = nullptr;
611 bool ret = false;
612 char tmpStr[BUF_SIZE_TINY] = "";
613 int busNum = 0;
614 int devNum = 0;
615 int curBus = 0;
616 int curDev = 0;
617
618 int device_num = libusb_get_device_list(ctxUSB, &listDevices);
619 WRITE_LOG(LOG_DEBUG, "device_num:%d", device_num);
620 if (device_num <= 0) {
621 libusb_free_device_list(listDevices, 1);
622 return false;
623 }
624 WRITE_LOG(LOG_DEBUG, "usbMountPoint:%s", usbMountPoint);
625 if (strchr(usbMountPoint, '-') && EOK == strcpy_s(tmpStr, sizeof(tmpStr), usbMountPoint)) {
626 *strchr(tmpStr, '-') = '\0';
627 busNum = atoi(tmpStr);
628 devNum = atoi(tmpStr + strlen(tmpStr) + 1);
629 } else
630 return false;
631 WRITE_LOG(LOG_DEBUG, "busNum:%d devNum:%d", busNum, devNum);
632
633 int i = 0;
634 for (i = 0; i < device_num; ++i) {
635 struct libusb_device_descriptor desc;
636 if (LIBUSB_SUCCESS != libusb_get_device_descriptor(listDevices[i], &desc)) {
637 WRITE_LOG(LOG_DEBUG, "libusb_get_device_descriptor failed i:%d", i);
638 continue;
639 }
640 curBus = libusb_get_bus_number(listDevices[i]);
641 curDev = libusb_get_device_address(listDevices[i]);
642 WRITE_LOG(LOG_DEBUG, "curBus:%d curDev:%d", curBus, curDev);
643 if ((curBus == busNum && curDev == devNum)) {
644 hUSB->device = listDevices[i];
645 int childRet = OpenDeviceMyNeed(hUSB);
646 WRITE_LOG(LOG_DEBUG, "OpenDeviceMyNeed childRet:%d", childRet);
647 if (!childRet) {
648 ret = true;
649 }
650 break;
651 }
652 }
653 libusb_free_device_list(listDevices, 1);
654 return ret;
655 }
656
ReadyForWorkThread(HSession hSession)657 bool HdcHostUSB::ReadyForWorkThread(HSession hSession)
658 {
659 HdcUSBBase::ReadyForWorkThread(hSession);
660 return true;
661 };
662
663 // Determines that daemonInfo must have the device
ConnectDetectDaemon(const HSession hSession,const HDaemonInfo pdi)664 HSession HdcHostUSB::ConnectDetectDaemon(const HSession hSession, const HDaemonInfo pdi)
665 {
666 HdcServer *pServer = (HdcServer *)clsMainBase;
667 HUSB hUSB = hSession->hUSB;
668 hUSB->usbMountPoint = pdi->usbMountPoint;
669 hUSB->ctxUSB = ctxUSB;
670 if (!FindDeviceByID(hUSB, hUSB->usbMountPoint.c_str(), hUSB->ctxUSB)) {
671 pServer->FreeSession(hSession->sessionId);
672 return nullptr;
673 }
674 UpdateUSBDaemonInfo(hUSB, hSession, STATUS_CONNECTED);
675 BeginUsbRead(hSession);
676 hUSB->usbMountPoint = pdi->usbMountPoint;
677 WRITE_LOG(LOG_DEBUG, "HSession HdcHostUSB::ConnectDaemon");
678
679 Base::StartWorkThread(&pServer->loopMain, pServer->SessionWorkThread, Base::FinishWorkThread, hSession);
680 // wait for thread up
681 while (hSession->childLoop.active_handles == 0) {
682 uv_sleep(1);
683 }
684 auto ctrl = pServer->BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
685 Base::SendToStream((uv_stream_t *)&hSession->ctrlPipe[STREAM_MAIN], ctrl.data(), ctrl.size());
686 return hSession;
687 }
688 } // namespace Hdc
689