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 16#include "usbhost_sdkapi_speed.h" 17#include <dirent.h> 18#include <errno.h> 19#include <fcntl.h> 20#include <inttypes.h> 21#include <osal_sem.h> 22#include <osal_thread.h> 23#include <signal.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27#include <sys/ioctl.h> 28#include <sys/mman.h> 29#include <sys/time.h> 30#include <unistd.h> 31 32#include "hdf_base.h" 33#include "hdf_log.h" 34#include "hdf_usb_pnp_manage.h" 35#include "osal_mem.h" 36#include "osal_time.h" 37#include "securec.h" 38#include "usb_ddk_interface.h" 39 40#define HDF_LOG_TAG USB_HOST_ACM 41#define STRTOL_BASE 10 42 43static unsigned int g_speedFlag = 0; 44static uint64_t g_recv_count = 0; 45static uint64_t g_send_count = 0; 46static uint64_t g_byteTotal = 0; 47static bool g_writeOrRead = TEST_WRITE; 48static bool g_printData = false; 49 50static void AcmTestBulkCallback(struct UsbRequest *req); 51static int32_t SerialBegin(struct AcmDevice * const acm); 52 53static int32_t AcmDbAlloc(struct AcmDevice * const acm) 54{ 55 int32_t i, dbn; 56 struct AcmDb *db = NULL; 57 dbn = 0; 58 i = 0; 59 for (;;) { 60 db = &acm->db[dbn]; 61 if (!db->use) { 62 db->use = 1; 63 db->len = 0; 64 return dbn; 65 } 66 dbn = (dbn + 1) % TEST_CYCLE; 67 if (++i >= TEST_CYCLE) { 68 return -1; 69 } 70 } 71} 72 73static int32_t AcmDbIsAvail(struct AcmDevice * const acm) 74{ 75 int32_t i, n; 76 n = TEST_CYCLE; 77 for (i = 0; i < TEST_CYCLE; i++) 78 n -= acm->db[i].use; 79 return n; 80} 81 82static UsbInterfaceHandle *InterfaceIdToHandle(const struct AcmDevice *acm, uint8_t id) 83{ 84 (void)pipe; 85 UsbInterfaceHandle *devHandle = NULL; 86 87 if (id == 0xFF) { 88 devHandle = acm->ctrDevHandle; 89 } else { 90 for (int32_t i = 0; i < acm->interfaceCnt; i++) { 91 if (acm->iface[i]->info.interfaceIndex == id) { 92 devHandle = acm->devHandle[i]; 93 break; 94 } 95 } 96 } 97 return devHandle; 98} 99 100static int32_t AcmStartDb(struct AcmDevice *acm, struct AcmDb *db, struct UsbPipeInfo *pipe) 101{ 102 (void)acm; 103 (void)pipe; 104 int32_t rc; 105 rc = UsbSubmitRequestAsync(db->request); 106 if (rc < 0) { 107 HDF_LOGE("UsbSubmitRequestAsync failed, ret=%{public}d ", rc); 108 db->use = 0; 109 } 110 return rc; 111} 112 113static int32_t AcmDataBufAlloc(struct AcmDevice * const acm) 114{ 115 int32_t i; 116 struct AcmDb *db; 117 for (db = &acm->db[0], i = 0; i < TEST_CYCLE; i++, db++) { 118 db->buf = OsalMemCalloc(acm->dataSize); 119 if (!db->buf) { 120 while (i > 0) { 121 --i; 122 --db; 123 OsalMemFree(db->buf); 124 db->buf = NULL; 125 } 126 return -HDF_ERR_MALLOC_FAIL; 127 } else { 128 memset_s(db->buf, acm->dataSize, 'a', acm->dataSize); 129 db->instance = acm; 130 } 131 } 132 return 0; 133} 134 135static void AcmTestBulkCallback(struct UsbRequest *req) 136{ 137 if (req == NULL) { 138 printf("req is null\r\n"); 139 return; 140 } 141 int32_t status = req->compInfo.status; 142 struct AcmDb *db = (struct AcmDb *)req->compInfo.userData; 143 struct itimerval new_value, old_value; 144 145 if (status == 0) { 146 if (g_byteTotal == 0) { 147 new_value.it_value.tv_sec = TEST_PRINT_TIME; 148 new_value.it_value.tv_usec = 0; 149 new_value.it_interval.tv_sec = TEST_PRINT_TIME; 150 new_value.it_interval.tv_usec = 0; 151 setitimer(ITIMER_REAL, &new_value, &old_value); 152 } 153 g_recv_count++; 154 g_byteTotal += req->compInfo.actualLength; 155 } else { 156 printf("error status=%d\r\n", status); 157 } 158 159 if (g_printData) { 160 for (unsigned int i = 0; i < req->compInfo.actualLength; i++) { 161 printf("%c", req->compInfo.buffer[i]); 162 } 163 fflush(stdout); 164 } else if (g_recv_count % TEST_RECV_COUNT == 0) { 165 printf("#"); 166 fflush(stdout); 167 } 168 169 db->use = 0; 170 if (!g_speedFlag) { 171 if (SerialBegin(db->instance) != HDF_SUCCESS) { 172 HDF_LOGW("%{public}s:%{public}d SerialBegin error!", __func__, __LINE__); 173 } 174 g_send_count++; 175 } 176 177 return; 178} 179 180static int32_t SerialBegin(struct AcmDevice *acm) 181{ 182 uint32_t size = acm->dataSize; 183 int32_t dbn; 184 if (AcmDbIsAvail(acm) != 0) { 185 dbn = AcmDbAlloc(acm); 186 } else { 187 HDF_LOGE("no buf"); 188 return 0; 189 } 190 if (dbn < 0) { 191 HDF_LOGE("AcmDbAlloc failed"); 192 return HDF_FAILURE; 193 } 194 struct AcmDb *db = &acm->db[dbn]; 195 db->len = acm->dataSize; 196 int32_t ret = AcmStartDb(acm, db, NULL); 197 if (ret != HDF_SUCCESS) { 198 HDF_LOGE("acmstartdb is failed"); 199 return HDF_FAILURE; 200 } 201 return (int32_t)size; 202} 203 204static struct UsbInterface *GetUsbInterfaceById(const struct AcmDevice *acm, uint8_t interfaceIndex) 205{ 206 return UsbClaimInterface(acm->session, acm->busNum, acm->devAddr, interfaceIndex); 207} 208 209static struct UsbPipeInfo *EnumePipe( 210 const struct AcmDevice *acm, uint8_t interfaceIndex, UsbPipeType pipeType, UsbPipeDirection pipeDirection) 211{ 212 struct UsbInterfaceInfo *info = NULL; 213 UsbInterfaceHandle *interfaceHandle = NULL; 214 if (USB_PIPE_TYPE_CONTROL == pipeType) { 215 info = &acm->ctrIface->info; 216 interfaceHandle = acm->ctrDevHandle; 217 } else { 218 info = &acm->iface[interfaceIndex]->info; 219 interfaceHandle = InterfaceIdToHandle(acm, info->interfaceIndex); 220 } 221 222 for (uint8_t i = 0; i <= info->pipeNum; i++) { 223 struct UsbPipeInfo p; 224 int32_t ret = UsbGetPipeInfo(interfaceHandle, info->curAltSetting, i, &p); 225 if (ret < 0) { 226 continue; 227 } 228 if ((p.pipeDirection == pipeDirection) && (p.pipeType == pipeType)) { 229 struct UsbPipeInfo *pi = OsalMemCalloc(sizeof(*pi)); 230 if (pi == NULL) { 231 HDF_LOGE("%{public}s: Alloc pipe failed", __func__); 232 return NULL; 233 } 234 p.interfaceId = info->interfaceIndex; 235 *pi = p; 236 return pi; 237 } 238 } 239 return NULL; 240} 241 242static struct UsbPipeInfo *GetPipe(const struct AcmDevice *acm, UsbPipeType pipeType, UsbPipeDirection pipeDirection) 243{ 244 uint8_t i; 245 if (acm == NULL) { 246 HDF_LOGE("%{public}s: invalid parmas", __func__); 247 return NULL; 248 } 249 for (i = 0; i < acm->interfaceCnt; i++) { 250 struct UsbPipeInfo *p = NULL; 251 if (!acm->iface[i]) { 252 continue; 253 } 254 p = EnumePipe(acm, i, pipeType, pipeDirection); 255 if (p == NULL) { 256 continue; 257 } 258 return p; 259 } 260 return NULL; 261} 262 263static void SignalHandler(int32_t signo) 264{ 265 static uint32_t sigCnt = 0; 266 struct itimerval new_value, old_value; 267 double speed = 0; 268 switch (signo) { 269 case SIGALRM: 270 sigCnt++; 271 if (sigCnt * TEST_PRINT_TIME >= TEST_TIME) { 272 g_speedFlag = 1; 273 break; 274 } 275 speed = (g_byteTotal * TEST_FLOAT_COUNT) / (sigCnt * TEST_PRINT_TIME * TEST_BYTE_COUNT * TEST_BYTE_COUNT); 276 printf("\nSpeed:%f MB/s\n", speed); 277 new_value.it_value.tv_sec = TEST_PRINT_TIME; 278 new_value.it_value.tv_usec = 0; 279 new_value.it_interval.tv_sec = TEST_PRINT_TIME; 280 new_value.it_interval.tv_usec = 0; 281 setitimer(ITIMER_REAL, &new_value, &old_value); 282 break; 283 case SIGINT: 284 g_speedFlag = 1; 285 break; 286 default: 287 break; 288 } 289} 290 291static void ShowHelp(const char *name) 292{ 293 printf(">> usage:\n"); 294 printf(">> %s [<busNum> <devAddr>] <ifaceNum> <w>/<r> [printdata]> \n", name); 295 printf("\n"); 296} 297 298static struct AcmDevice *CheckParam(int32_t argc, const char *argv[]) 299{ 300 int32_t busNum = 1; 301 int32_t devAddr = 2; 302 int32_t ifaceNum = 3; 303 struct AcmDevice *acm = NULL; 304 305 if (argc == TEST_SIX_TYPE) { 306 busNum = (int32_t)strtol(argv[TEST_ONE_TYPE], NULL, STRTOL_BASE); 307 devAddr = (int32_t)strtol(argv[TEST_TWO_TYPE], NULL, STRTOL_BASE); 308 ifaceNum = (int32_t)strtol(argv[TEST_THREE_TYPE], NULL, STRTOL_BASE); 309 g_writeOrRead = (strncmp(argv[TEST_FOUR_TYPE], "r", TEST_ONE_TYPE)) ? TEST_WRITE : TEST_READ; 310 if (g_writeOrRead == TEST_READ) { 311 g_printData = (strncmp(argv[TEST_FIVE_TYPE], "printdata", TEST_ONE_TYPE)) ? false : true; 312 } 313 } else if (argc == TEST_FIVE_TYPE) { 314 busNum = (int32_t)strtol(argv[TEST_ONE_TYPE], NULL, STRTOL_BASE); 315 devAddr = (int32_t)strtol(argv[TEST_TWO_TYPE], NULL, STRTOL_BASE); 316 ifaceNum = (int32_t)strtol(argv[TEST_THREE_TYPE], NULL, STRTOL_BASE); 317 g_writeOrRead = (strncmp(argv[TEST_FOUR_TYPE], "r", TEST_ONE_TYPE)) ? TEST_WRITE : TEST_READ; 318 } else if (argc == TEST_THREE_TYPE) { 319 ifaceNum = (int32_t)strtol(argv[TEST_ONE_TYPE], NULL, STRTOL_BASE); 320 g_writeOrRead = (strncmp(argv[TEST_TWO_TYPE], "r", TEST_ONE_TYPE)) ? TEST_WRITE : TEST_READ; 321 } else { 322 printf("Error: parameter error!\n\n"); 323 ShowHelp(argv[0]); 324 goto END; 325 } 326 327 acm = (struct AcmDevice *)OsalMemCalloc(sizeof(*acm)); 328 if (acm == NULL) { 329 HDF_LOGE("%{public}s: Alloc usb serial device failed", __func__); 330 goto END; 331 } 332 acm->busNum = busNum; 333 acm->devAddr = devAddr; 334 acm->interfaceCnt = 1; 335 acm->interfaceIndex[0] = ifaceNum; 336END: 337 return acm; 338} 339 340static int32_t InitUsbDdk(struct AcmDevice *acm) 341{ 342 int32_t ret = UsbInitHostSdk(NULL); 343 if (ret != HDF_SUCCESS) { 344 HDF_LOGE("%{public}s: UsbInitHostSdk failed", __func__); 345 ret = HDF_ERR_IO; 346 goto END; 347 } 348 349 for (int32_t i = 0; i < acm->interfaceCnt; i++) { 350 acm->iface[i] = GetUsbInterfaceById((const struct AcmDevice *)acm, acm->interfaceIndex[i]); 351 } 352 353 for (int32_t i = 0; i < acm->interfaceCnt; i++) { 354 if (acm->iface[i]) { 355 acm->devHandle[i] = UsbOpenInterface(acm->iface[i]); 356 if (acm->devHandle[i] == NULL) { 357 HDF_LOGE("%{public}s: UsbOpenInterface null", __func__); 358 } 359 } else { 360 ret = HDF_FAILURE; 361 goto END; 362 } 363 } 364 if (g_writeOrRead == TEST_WRITE) { 365 acm->dataPipe = GetPipe(acm, USB_PIPE_TYPE_BULK, USB_PIPE_DIRECTION_OUT); 366 } else { 367 acm->dataPipe = GetPipe(acm, USB_PIPE_TYPE_BULK, USB_PIPE_DIRECTION_IN); 368 } 369 if (acm->dataPipe == NULL) { 370 HDF_LOGE("dataPipe is NULL"); 371 } 372 373 acm->dataSize = TEST_LENGTH; 374 if (AcmDataBufAlloc(acm) < 0) { 375 HDF_LOGE("%{public}s:%{public}d AcmDataBufAlloc fail", __func__, __LINE__); 376 } 377END: 378 return ret; 379} 380 381static int32_t FillRequest(struct AcmDevice * const acm) 382{ 383 for (int32_t i = 0; i < TEST_CYCLE; i++) { 384 struct AcmDb *snd = &(acm->db[i]); 385 snd->request = UsbAllocRequest(InterfaceIdToHandle(acm, acm->dataPipe->interfaceId), 0, acm->dataSize); 386 if (snd->request == NULL) { 387 HDF_LOGE("%{public}s:%{public}d snd request fail", __func__, __LINE__); 388 } 389 int32_t rc; 390 acm->transmitting++; 391 struct UsbRequestParams parmas = {}; 392 parmas.interfaceId = acm->dataPipe->interfaceId; 393 parmas.pipeAddress = acm->dataPipe->pipeAddress; 394 parmas.pipeId = acm->dataPipe->pipeId; 395 parmas.callback = AcmTestBulkCallback; 396 parmas.requestType = USB_REQUEST_PARAMS_DATA_TYPE; 397 parmas.timeout = USB_CTRL_SET_TIMEOUT; 398 parmas.dataReq.numIsoPackets = 0; 399 parmas.userData = (void *)snd; 400 parmas.dataReq.length = acm->dataSize; 401 parmas.dataReq.buffer = snd->buf; 402 parmas.dataReq.directon = (acm->dataPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & 0x1; 403 snd->dbNum = acm->transmitting; 404 rc = UsbFillRequest(snd->request, InterfaceIdToHandle(acm, acm->dataPipe->interfaceId), &parmas); 405 if (rc != HDF_SUCCESS) { 406 HDF_LOGE("%{public}s:UsbFillRequest failed,ret=%{public}d ", __func__, rc); 407 return rc; 408 } 409 } 410 411 return HDF_SUCCESS; 412} 413 414int32_t main(int32_t argc, char *argv[]) 415{ 416 struct timeval time; 417 int32_t i; 418 int32_t ret; 419 struct AcmDevice *acm = NULL; 420 421 acm = CheckParam(argc, (const char **)argv); 422 if (acm == NULL) { 423 ret = HDF_FAILURE; 424 goto END; 425 } 426 427 ret = InitUsbDdk(acm); 428 if (ret != HDF_SUCCESS) { 429 goto END; 430 } 431 432 ret = FillRequest(acm); 433 if (ret != HDF_SUCCESS) { 434 goto END; 435 } 436 437 if (signal(SIGINT, SignalHandler) == SIG_ERR) { 438 HDF_LOGE("signal SIGINT failed"); 439 return HDF_FAILURE; 440 } 441 if (signal(SIGALRM, SignalHandler) == SIG_ERR) { 442 HDF_LOGE("signal SIGINT failed"); 443 return HDF_FAILURE; 444 } 445 gettimeofday(&time, NULL); 446 447 printf("test SDK API [%s]\n", g_writeOrRead ? "write" : "read"); 448 for (i = 0; i < TEST_CYCLE; i++) { 449 if (SerialBegin(acm) != HDF_SUCCESS) { 450 HDF_LOGW("%{public}s:%{public}d SerialBegin error!", __func__, __LINE__); 451 } 452 g_send_count++; 453 } 454 455 while (!g_speedFlag) { 456 OsalMSleep(TEST_SLEEP_TIME); 457 } 458END: 459 if (ret != HDF_SUCCESS) { 460 printf("please check whether usb drv so is existing or not,like acm,ecm,if not, remove it and test again!\n"); 461 } 462 return ret; 463} 464