1cc290419Sopenharmony_ci/* 2cc290419Sopenharmony_ci * Copyright (C) 2021 Huawei Device Co., Ltd. 3cc290419Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4cc290419Sopenharmony_ci * you may not use this file except in compliance with the License. 5cc290419Sopenharmony_ci * You may obtain a copy of the License at 6cc290419Sopenharmony_ci * 7cc290419Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8cc290419Sopenharmony_ci * 9cc290419Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10cc290419Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11cc290419Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12cc290419Sopenharmony_ci * See the License for the specific language governing permissions and 13cc290419Sopenharmony_ci * limitations under the License. 14cc290419Sopenharmony_ci */ 15cc290419Sopenharmony_ci#include "usb.h" 16cc290419Sopenharmony_ci 17cc290419Sopenharmony_cinamespace Hdc { 18cc290419Sopenharmony_ciHdcUSBBase::HdcUSBBase(const bool serverOrDaemonIn, void *ptrMainBase) 19cc290419Sopenharmony_ci{ 20cc290419Sopenharmony_ci serverOrDaemon = serverOrDaemonIn; 21cc290419Sopenharmony_ci clsMainBase = ptrMainBase; 22cc290419Sopenharmony_ci modRunning = true; 23cc290419Sopenharmony_ci} 24cc290419Sopenharmony_ci 25cc290419Sopenharmony_ciHdcUSBBase::~HdcUSBBase() 26cc290419Sopenharmony_ci{ 27cc290419Sopenharmony_ci} 28cc290419Sopenharmony_ci 29cc290419Sopenharmony_civoid HdcUSBBase::ReadUSB(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) 30cc290419Sopenharmony_ci{ 31cc290419Sopenharmony_ci StartTraceScope("HdcUSBBase::ReadUSB"); 32cc290419Sopenharmony_ci HSession hSession = (HSession)stream->data; 33cc290419Sopenharmony_ci HdcSessionBase *hSessionBase = (HdcSessionBase *)hSession->classInstance; 34cc290419Sopenharmony_ci if (hSessionBase->FetchIOBuf(hSession, hSession->ioBuf, nread) < 0) { 35cc290419Sopenharmony_ci WRITE_LOG(LOG_FATAL, "ReadUSB FetchIOBuf error sessionId:%u", hSession->sessionId); 36cc290419Sopenharmony_ci hSessionBase->FreeSession(hSession->sessionId); 37cc290419Sopenharmony_ci } 38cc290419Sopenharmony_ci} 39cc290419Sopenharmony_ci 40cc290419Sopenharmony_cibool HdcUSBBase::ReadyForWorkThread(HSession hSession) 41cc290419Sopenharmony_ci{ 42cc290419Sopenharmony_ci // Server-end USB IO is handed over to each sub-thread, only the daemon is still read by the main IO to distribute 43cc290419Sopenharmony_ci // to each sub-thread by DataPipe. 44cc290419Sopenharmony_ci if (uv_tcp_init(&hSession->childLoop, &hSession->dataPipe[STREAM_WORK]) || 45cc290419Sopenharmony_ci uv_tcp_open(&hSession->dataPipe[STREAM_WORK], hSession->dataFd[STREAM_WORK])) { 46cc290419Sopenharmony_ci WRITE_LOG(LOG_FATAL, "USBBase ReadyForWorkThread init child TCP failed"); 47cc290419Sopenharmony_ci return false; 48cc290419Sopenharmony_ci } 49cc290419Sopenharmony_ci hSession->dataPipe[STREAM_WORK].data = hSession; 50cc290419Sopenharmony_ci HdcSessionBase *pSession = (HdcSessionBase *)hSession->classInstance; 51cc290419Sopenharmony_ci#ifdef HDC_HOST 52cc290419Sopenharmony_ci Base::SetTcpOptions(&hSession->dataPipe[STREAM_WORK], HOST_SOCKETPAIR_SIZE); 53cc290419Sopenharmony_ci#else 54cc290419Sopenharmony_ci Base::SetTcpOptions(&hSession->dataPipe[STREAM_WORK]); 55cc290419Sopenharmony_ci#endif 56cc290419Sopenharmony_ci if (uv_read_start((uv_stream_t *)&hSession->dataPipe[STREAM_WORK], pSession->AllocCallback, ReadUSB)) { 57cc290419Sopenharmony_ci WRITE_LOG(LOG_FATAL, "USBBase ReadyForWorkThread child TCP read failed"); 58cc290419Sopenharmony_ci return false; 59cc290419Sopenharmony_ci } 60cc290419Sopenharmony_ci WRITE_LOG(LOG_DEBUG, "USBBase ReadyForWorkThread finish dataFd[STREAM_WORK]:%d", 61cc290419Sopenharmony_ci hSession->dataFd[STREAM_WORK]); 62cc290419Sopenharmony_ci return true; 63cc290419Sopenharmony_ci}; 64cc290419Sopenharmony_ci 65cc290419Sopenharmony_civector<uint8_t> HdcUSBBase::BuildPacketHeader(uint32_t sessionId, uint8_t option, uint32_t dataSize) 66cc290419Sopenharmony_ci{ 67cc290419Sopenharmony_ci vector<uint8_t> vecData; 68cc290419Sopenharmony_ci USBHead head; 69cc290419Sopenharmony_ci head.sessionId = htonl(sessionId); 70cc290419Sopenharmony_ci for (size_t i = 0; i < sizeof(head.flag); i++) { 71cc290419Sopenharmony_ci head.flag[i] = USB_PACKET_FLAG.data()[i]; 72cc290419Sopenharmony_ci } 73cc290419Sopenharmony_ci head.option = option; 74cc290419Sopenharmony_ci head.dataSize = htonl(dataSize); 75cc290419Sopenharmony_ci vecData.insert(vecData.end(), (uint8_t *)&head, (uint8_t *)&head + sizeof(USBHead)); 76cc290419Sopenharmony_ci return vecData; 77cc290419Sopenharmony_ci} 78cc290419Sopenharmony_ci 79cc290419Sopenharmony_ci// USB big data stream, block transmission, mainly to prevent accidental data packets from writing through EP port, 80cc290419Sopenharmony_ci// inserting the send queue causes the program to crash 81cc290419Sopenharmony_ciint HdcUSBBase::SendUSBBlock(HSession hSession, uint8_t *data, const int length) 82cc290419Sopenharmony_ci{ 83cc290419Sopenharmony_ci int childRet = 0; 84cc290419Sopenharmony_ci int ret = ERR_IO_FAIL; 85cc290419Sopenharmony_ci StartTraceScope("HdcUSBBase::SendUSBBlock"); 86cc290419Sopenharmony_ci std::lock_guard<std::mutex> lock(hSession->hUSB->lockSendUsbBlock); 87cc290419Sopenharmony_ci auto header = BuildPacketHeader(hSession->sessionId, USB_OPTION_HEADER, length); 88cc290419Sopenharmony_ci do { 89cc290419Sopenharmony_ci if ((SendUSBRaw(hSession, header.data(), header.size())) <= 0) { 90cc290419Sopenharmony_ci WRITE_LOG(LOG_FATAL, "SendUSBRaw index failed"); 91cc290419Sopenharmony_ci break; 92cc290419Sopenharmony_ci } 93cc290419Sopenharmony_ci if ((childRet = SendUSBRaw(hSession, data, length)) <= 0) { 94cc290419Sopenharmony_ci WRITE_LOG(LOG_FATAL, "SendUSBRaw body failed"); 95cc290419Sopenharmony_ci break; 96cc290419Sopenharmony_ci } 97cc290419Sopenharmony_ci if (childRet > 0 && (childRet % hSession->hUSB->wMaxPacketSizeSend == 0)) { 98cc290419Sopenharmony_ci // win32 send ZLP will block winusb driver and LIBUSB_TRANSFER_ADD_ZERO_PACKET not effect 99cc290419Sopenharmony_ci // so, we send dummy packet to prevent zero packet generate 100cc290419Sopenharmony_ci auto dummy = BuildPacketHeader(hSession->sessionId, 0, 0); 101cc290419Sopenharmony_ci if ((SendUSBRaw(hSession, dummy.data(), dummy.size())) <= 0) { 102cc290419Sopenharmony_ci WRITE_LOG(LOG_FATAL, "SendUSBRaw dummy failed"); 103cc290419Sopenharmony_ci break; 104cc290419Sopenharmony_ci } 105cc290419Sopenharmony_ci } 106cc290419Sopenharmony_ci ret = length; 107cc290419Sopenharmony_ci } while (false); 108cc290419Sopenharmony_ci return ret; 109cc290419Sopenharmony_ci} 110cc290419Sopenharmony_ci 111cc290419Sopenharmony_cibool HdcUSBBase::IsUsbPacketHeader(uint8_t *ioBuf, int ioBytes) 112cc290419Sopenharmony_ci{ 113cc290419Sopenharmony_ci StartTraceScope("HdcUSBBase::IsUsbPacketHeader"); 114cc290419Sopenharmony_ci USBHead *usbPayloadHeader = reinterpret_cast<struct USBHead *>(ioBuf); 115cc290419Sopenharmony_ci uint32_t maybeSize = ntohl(usbPayloadHeader->dataSize); 116cc290419Sopenharmony_ci bool isHeader = false; 117cc290419Sopenharmony_ci do { 118cc290419Sopenharmony_ci if (memcmp(usbPayloadHeader->flag, USB_PACKET_FLAG.c_str(), USB_PACKET_FLAG.size())) { 119cc290419Sopenharmony_ci break; 120cc290419Sopenharmony_ci } 121cc290419Sopenharmony_ci if (ioBytes != sizeof(USBHead)) { 122cc290419Sopenharmony_ci break; 123cc290419Sopenharmony_ci } 124cc290419Sopenharmony_ci if (maybeSize == 0) { 125cc290419Sopenharmony_ci isHeader = true; // nop packet 126cc290419Sopenharmony_ci break; 127cc290419Sopenharmony_ci } else { // maybeSize != 0 128cc290419Sopenharmony_ci if (usbPayloadHeader->option & USB_OPTION_HEADER) { 129cc290419Sopenharmony_ci isHeader = true; 130cc290419Sopenharmony_ci break; 131cc290419Sopenharmony_ci } 132cc290419Sopenharmony_ci } 133cc290419Sopenharmony_ci } while (false); 134cc290419Sopenharmony_ci return isHeader; 135cc290419Sopenharmony_ci} 136cc290419Sopenharmony_ci 137cc290419Sopenharmony_civoid HdcUSBBase::PreSendUsbSoftReset(HSession hSession, uint32_t sessionIdOld) 138cc290419Sopenharmony_ci{ 139cc290419Sopenharmony_ci StartTraceScope("HdcUSBBase::PreSendUsbSoftReset"); 140cc290419Sopenharmony_ci HUSB hUSB = hSession->hUSB; 141cc290419Sopenharmony_ci if (hSession->serverOrDaemon && !hUSB->resetIO) { 142cc290419Sopenharmony_ci hUSB->lockSendUsbBlock.lock(); 143cc290419Sopenharmony_ci WRITE_LOG(LOG_WARN, "SendToHdcStream check, sessionId not matched"); 144cc290419Sopenharmony_ci auto header = BuildPacketHeader(sessionIdOld, USB_OPTION_RESET, 0); 145cc290419Sopenharmony_ci if (SendUSBRaw(hSession, header.data(), header.size()) <= 0) { 146cc290419Sopenharmony_ci WRITE_LOG(LOG_FATAL, "PreSendUsbSoftReset send failed"); 147cc290419Sopenharmony_ci } 148cc290419Sopenharmony_ci hUSB->lockSendUsbBlock.unlock(); 149cc290419Sopenharmony_ci hUSB->resetIO = true; 150cc290419Sopenharmony_ci } 151cc290419Sopenharmony_ci} 152cc290419Sopenharmony_ci 153cc290419Sopenharmony_ciint HdcUSBBase::CheckPacketOption(HSession hSession, uint8_t *appendData, int dataSize) 154cc290419Sopenharmony_ci{ 155cc290419Sopenharmony_ci HUSB hUSB = hSession->hUSB; 156cc290419Sopenharmony_ci // special short packet 157cc290419Sopenharmony_ci USBHead *header = reinterpret_cast<USBHead *>(appendData); 158cc290419Sopenharmony_ci header->sessionId = ntohl(header->sessionId); 159cc290419Sopenharmony_ci header->dataSize = ntohl(header->dataSize); 160cc290419Sopenharmony_ci if (header->sessionId != hSession->sessionId) { 161cc290419Sopenharmony_ci // Only server do it here, daemon 'SendUsbSoftReset' no use 162cc290419Sopenharmony_ci // hilog + ctrl^C to reproduction scene 163cc290419Sopenharmony_ci // 164cc290419Sopenharmony_ci // Because the USB-reset API does not work on all platforms, the last session IO data may be 165cc290419Sopenharmony_ci // recveived, we need to ignore it. 166cc290419Sopenharmony_ci WRITE_LOG(LOG_WARN, "CheckPacketOption softreset header->sessionId:%u sessionId:%u", 167cc290419Sopenharmony_ci header->sessionId, hSession->sessionId); 168cc290419Sopenharmony_ci PreSendUsbSoftReset(hSession, header->sessionId); 169cc290419Sopenharmony_ci return 0; 170cc290419Sopenharmony_ci } 171cc290419Sopenharmony_ci if (header->option & USB_OPTION_HEADER) { 172cc290419Sopenharmony_ci // header packet 173cc290419Sopenharmony_ci hUSB->payloadSize = header->dataSize; 174cc290419Sopenharmony_ci } 175cc290419Sopenharmony_ci // soft ZLP 176cc290419Sopenharmony_ci return hUSB->payloadSize; 177cc290419Sopenharmony_ci} 178cc290419Sopenharmony_ci 179cc290419Sopenharmony_ci// return value: <0 error; = 0 all finish; >0 need size 180cc290419Sopenharmony_ciint HdcUSBBase::SendToHdcStream(HSession hSession, uv_stream_t *stream, uint8_t *appendData, int dataSize) 181cc290419Sopenharmony_ci{ 182cc290419Sopenharmony_ci StartTraceScope("HdcUSBBase::SendToHdcStream"); 183cc290419Sopenharmony_ci int childRet = 0; 184cc290419Sopenharmony_ci HUSB hUSB = hSession->hUSB; 185cc290419Sopenharmony_ci if (IsUsbPacketHeader(appendData, dataSize)) { 186cc290419Sopenharmony_ci return CheckPacketOption(hSession, appendData, dataSize); 187cc290419Sopenharmony_ci } 188cc290419Sopenharmony_ci if (hUSB->payloadSize <= static_cast<uint32_t>(childRet)) { 189cc290419Sopenharmony_ci // last session data 190cc290419Sopenharmony_ci WRITE_LOG(LOG_WARN, "SendToHdcStream softreset dataSize:%d payloadSize:%u childRet:%d", 191cc290419Sopenharmony_ci dataSize, hUSB->payloadSize, childRet); 192cc290419Sopenharmony_ci PreSendUsbSoftReset(hSession, 0); // 0 == reset current 193cc290419Sopenharmony_ci return 0; 194cc290419Sopenharmony_ci } 195cc290419Sopenharmony_ci if ((childRet = UsbToHdcProtocol(stream, appendData, dataSize)) < 0) { 196cc290419Sopenharmony_ci WRITE_LOG(LOG_FATAL, "Error usb send to stream dataSize:%d", dataSize); 197cc290419Sopenharmony_ci return ERR_IO_FAIL; 198cc290419Sopenharmony_ci } 199cc290419Sopenharmony_ci hUSB->payloadSize -= childRet; 200cc290419Sopenharmony_ci return hUSB->payloadSize; 201cc290419Sopenharmony_ci} 202cc290419Sopenharmony_ci 203cc290419Sopenharmony_ci} 204