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