* Copyright (C) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "oh_usb.h"
#include "usb_ffs.h"
#include "usb_util.h"
#include "sys_para.h"
#include "log.h"
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <csignal>
using namespace Hdc;
static constexpr int CONFIG_COUNT2 = 2;
static constexpr int CONFIG_COUNT3 = 3;
static constexpr int CONFIG_COUNT5 = 5;
void FillUsbV2Head(struct Hdc::UsbFunctionfsDescV2 &descUsbFfs)
{
descUsbFfs.head.magic = LONG_LE(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
descUsbFfs.head.length = LONG_LE(sizeof(descUsbFfs));
descUsbFfs.head.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
descUsbFfs.config1Count = CONFIG_COUNT3;
descUsbFfs.config2Count = CONFIG_COUNT3;
descUsbFfs.config3Count = CONFIG_COUNT5;
descUsbFfs.configWosCount = CONFIG_COUNT2;
descUsbFfs.config1Desc = Hdc::config1;
descUsbFfs.config2Desc = Hdc::config2;
descUsbFfs.config3Desc = Hdc::config3;
descUsbFfs.wosHead = Hdc::g_wosHead;
descUsbFfs.wosDesc = Hdc::g_wosDesc;
descUsbFfs.osPropHead = Hdc::g_osPropHead;
descUsbFfs.osPropValues = Hdc::g_osPropValues;
}
int ConfigEpPoint(int& controlEp, const std::string& path)
{
struct Hdc::UsbFunctionfsDescV2 descUsbFfs = {};
FillUsbV2Head(descUsbFfs);
while (true) {
if (controlEp <= 0) {
WRITE_LOG(LOG_INFO, "Begin send to control(EP0) for usb descriptor init\n");
if ((controlEp = open(path.c_str(), O_RDWR)) < 0) {
WRITE_LOG(LOG_WARN, "%s: cannot open control endpoint: errno=%d\n", path.c_str(), errno);
break;
}
if (write(controlEp, &descUsbFfs, sizeof(descUsbFfs)) < 0) {
WRITE_LOG(LOG_WARN, "%s: write ffs configs failed: errno=%d\n", path.c_str(), errno);
break;
}
if (write(controlEp, &Hdc::USB_FFS_VALUE, sizeof(Hdc::USB_FFS_VALUE)) < 0) {
WRITE_LOG(LOG_WARN, "%s: write USB_FFS_VALUE failed: errno=%d\n", path.c_str(), errno);
break;
}
WRITE_LOG(LOG_INFO, "ConnectEPPoint ctrl init finish, set usb-ffs ready\n");
fcntl(controlEp, F_SETFD, FD_CLOEXEC);
Hdc::SetDevItem("sys.usb.ffs.ready.hdc", "0");
Hdc::SetDevItem("sys.usb.ffs.ready", "1");
Hdc::SetDevItem("sys.usb.ffs.ready.hdc", "1");
return ERR_SUCCESS;
}
}
return ERR_GENERIC;
}
int OpenEpPoint(int &fd, const std::string path)
{
if ((fd = open(path.c_str(), O_RDWR)) < 0) {
WRITE_LOG(LOG_WARN, "%s: cannot open ep: errno=%d\n", path.c_str(), errno);
return ERR_GENERIC;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
return ERR_SUCCESS;
}
int CloseUsbFd(int &fd)
{
int rc = 0;
#ifndef HDC_HOST
WRITE_LOG(LOG_INFO, "CloseFd fd:%d\n", fd);
#endif
if (fd > 0) {
rc = close(fd);
if (rc < 0) {
char buffer[Hdc::BUF_SIZE_DEFAULT] = { 0 };
#ifdef _WIN32
strerror_s(buffer, Hdc::BUF_SIZE_DEFAULT, errno);
#else
strerror_r(errno, buffer, Hdc::BUF_SIZE_DEFAULT);
#endif
WRITE_LOG(LOG_WARN, "close failed errno:%d %s\n", errno, buffer);
} else {
fd = -1;
}
}
return rc;
}
void CloseEndpoint(int &bulkInFd, int &bulkOutFd, int &controlEp, bool closeCtrlEp)
{
CloseUsbFd(bulkInFd);
CloseUsbFd(bulkOutFd);
if (controlEp > 0 && closeCtrlEp) {
CloseUsbFd(controlEp);
controlEp = 0;
}
WRITE_LOG(LOG_INFO, "close endpoint ok\n");
}
int WriteData(int bulkIn, const uint8_t *data, const int length)
{
int ret;
int writen = 0;
bool restoreSigmask = true;
sigset_t newmask;
sigset_t oldmask;
sigemptyset(&newmask);
sigaddset(&newmask, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
WRITE_LOG(LOG_FATAL, "before write usb, ignor the sigchld failed, err(%d)\n", errno);
restoreSigmask = false;
}
while (writen < length) {
ret = write(bulkIn, const_cast<uint8_t *>(data + writen), length - writen);
if (ret < 0) {
if (errno == EINTR) {
WRITE_LOG(LOG_FATAL, "write usb fd(%d) (%d) bytes interrupted, will retry\n",
bulkIn, length - writen);
continue;
}
WRITE_LOG(LOG_FATAL, "write usb fd(%d) (%d) bytes failed(%d), err(%d)\n",
bulkIn, length - writen, ret, errno);
break;
}
writen += ret;
}
if (restoreSigmask && sigprocmask(SIG_SETMASK, &oldmask, nullptr) < 0) {
WRITE_LOG(LOG_FATAL, "after write usb, restore signal mask failed, err(%d)\n", errno);
}
return ret < 0 ? ret : writen;
}
size_t ReadData(int bulkOut, uint8_t* buf, const size_t size)
{
int ret = -1;
size_t readed = 0;
while (readed < size) {
ret = read(bulkOut, buf + readed, size - readed);
if (ret >= 0) {
readed += static_cast<size_t>(ret);
} else if (errno == EINTR) {
WRITE_LOG(LOG_FATAL, "read usb fd(%d) (%d) bytes interrupted, will retry\n",
bulkOut, size - readed);
continue;
} else {
WRITE_LOG(LOG_FATAL, "read usb fd(%d) (%d) bytes failed(%d), err(%d)\n",
bulkOut, size - readed, ret, errno);
break;
}
}
return ret < 0 ? 0 : readed;
}