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 <osal_sem.h>
21 #include <osal_thread.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/ioctl.h>
27 #include <sys/mman.h>
28 #include <sys/time.h>
29 #include <unistd.h>
30
31 #include "hdf_base.h"
32 #include "hdf_log.h"
33 #include "hdf_usb_pnp_manage.h"
34 #include "implementation/global_implementation.h"
35 #include "osal_mem.h"
36 #include "osal_time.h"
37 #include "securec.h"
38 #include "usb_ddk_interface.h"
39 #include "usb_pnp_notify.h"
40
41 #define HDF_LOG_TAG USB_HOST_ACM
42
43 static bool g_speedFlag = false;
44 static uint64_t g_recv_count = 0;
45 static uint64_t g_send_count = 0;
46 static uint64_t g_byteTotal = 0;
47 static bool g_writeOrRead = TEST_WRITE;
48 static bool g_printData = false;
49 static struct AcmDevice *g_acm = NULL;
50 static struct OsalSem timeSem;
51 static uint32_t sigCnt = 0;
52
53 static void AcmTestBulkCallback(struct UsbRequest *req);
54 static int32_t SerialBegin(struct AcmDevice * const acm);
55
AcmDbAlloc(struct AcmDevice * acm)56 static int32_t AcmDbAlloc(struct AcmDevice *acm)
57 {
58 int32_t i, dbn;
59 struct AcmDb *db = NULL;
60 dbn = 0;
61 i = 0;
62 while (true) {
63 if (TEST_CYCLE <= dbn) {
64 return -1;
65 }
66 db = &acm->db[dbn];
67 if (!db->use) {
68 db->use = 1;
69 db->len = 0;
70 return dbn;
71 }
72 dbn = (dbn + 1) % TEST_CYCLE;
73 if (++i >= TEST_CYCLE) {
74 return -1;
75 }
76 }
77 }
78
AcmDbIsAvail(const struct AcmDevice * acm)79 static int32_t AcmDbIsAvail(const struct AcmDevice *acm)
80 {
81 int32_t i, n;
82 n = TEST_CYCLE;
83 for (i = 0; i < TEST_CYCLE; i++) {
84 n -= acm->db[i].use;
85 }
86 return n;
87 }
88
InterfaceIdToHandle(const struct AcmDevice * acm,uint8_t id)89 static UsbInterfaceHandle *InterfaceIdToHandle(const struct AcmDevice *acm, uint8_t id)
90 {
91 UsbInterfaceHandle *devHandle = NULL;
92
93 if (id == 0xFF) {
94 devHandle = acm->ctrDevHandle;
95 } else {
96 for (int32_t i = 0; i < acm->interfaceCnt; i++) {
97 if (acm->iface[i]->info.interfaceIndex == id) {
98 devHandle = acm->devHandle[i];
99 break;
100 }
101 }
102 }
103 return devHandle;
104 }
105
AcmStartDb(struct AcmDevice * acm,struct AcmDb * const db,struct UsbPipeInfo * pipe)106 static int32_t AcmStartDb(struct AcmDevice *acm, struct AcmDb * const db, struct UsbPipeInfo *pipe)
107 {
108 (void)acm;
109 (void)pipe;
110 int32_t rc;
111 rc = UsbSubmitRequestAsync(db->request);
112 if (rc < 0) {
113 HDF_LOGE("UsbSubmitRequestAsync failed, ret=%{public}d ", rc);
114 db->use = 0;
115 }
116 return rc;
117 }
118
AcmDataBufAlloc(struct AcmDevice * acm)119 static int32_t AcmDataBufAlloc(struct AcmDevice *acm)
120 {
121 int32_t i;
122 struct AcmDb *db = NULL;
123 if (acm == NULL) {
124 return 0;
125 }
126 for (db = &acm->db[0], i = 0; i < TEST_CYCLE; i++, db++) {
127 db->buf = OsalMemCalloc(acm->dataSize);
128 if (!db->buf) {
129 while (i != 0) {
130 --i;
131 --db;
132 OsalMemFree(db->buf);
133 db->buf = NULL;
134 }
135 return -HDF_ERR_MALLOC_FAIL;
136 } else {
137 memset_s(db->buf, acm->dataSize, 'a', acm->dataSize);
138 db->instance = acm;
139 }
140 }
141 return 0;
142 }
143
AcmDataBufFree(const struct AcmDevice * acm)144 static int32_t AcmDataBufFree(const struct AcmDevice *acm)
145 {
146 int32_t i;
147 struct AcmDb *db;
148 for (db = (struct AcmDb *)&acm->db[0], i = 0; i < TEST_CYCLE; i++, db++) {
149 OsalMemFree(db->buf);
150 db->use = 0;
151 }
152 return 0;
153 }
154
AcmTestBulkCallback(struct UsbRequest * req)155 static void AcmTestBulkCallback(struct UsbRequest *req)
156 {
157 if (req == NULL) {
158 printf("req is null\r\n");
159 return;
160 }
161 int32_t status = req->compInfo.status;
162 struct AcmDb *db = (struct AcmDb *)req->compInfo.userData;
163 if (status == 0) {
164 if (g_byteTotal == 0) {
165 OsalSemPost(&timeSem);
166 }
167 g_recv_count++;
168 g_byteTotal += req->compInfo.actualLength;
169 } else {
170 printf("error status=%d\r\n", status);
171 }
172
173 if (g_printData) {
174 for (unsigned int i = 0; i < req->compInfo.actualLength; i++) {
175 printf("%c", req->compInfo.buffer[i]);
176 }
177 fflush(stdout);
178 } else if (g_recv_count % TEST_RECV_COUNT == 0) {
179 printf("#");
180 fflush(stdout);
181 }
182 if (db == NULL) {
183 return;
184 }
185 db->use = 0;
186 if (!g_speedFlag) {
187 if (SerialBegin(db->instance) != HDF_SUCCESS) {
188 HDF_LOGW("%{public}s:%{public}d SerialBegin error!", __func__, __LINE__);
189 }
190 g_send_count++;
191 }
192 }
193
SerialBegin(struct AcmDevice * const acm)194 static int32_t SerialBegin(struct AcmDevice * const acm)
195 {
196 int32_t ret;
197 struct AcmDb *db = NULL;
198 int32_t dbn;
199 if (AcmDbIsAvail(acm) != 0) {
200 dbn = AcmDbAlloc(acm);
201 } else {
202 HDF_LOGE("no buf");
203 return 0;
204 }
205 if (dbn < 0) {
206 HDF_LOGE("AcmDbAlloc failed");
207 return HDF_FAILURE;
208 }
209 db = &acm->db[dbn];
210 db->len = (int)acm->dataSize;
211 ret = AcmStartDb(acm, db, NULL);
212 return ret;
213 }
214
GetUsbInterfaceById(const struct AcmDevice * acm,uint8_t interfaceIndex)215 static struct UsbInterface *GetUsbInterfaceById(const struct AcmDevice *acm, uint8_t interfaceIndex)
216 {
217 return UsbClaimInterface(NULL, acm->busNum, acm->devAddr, interfaceIndex);
218 }
219
EnumePipe(const struct AcmDevice * acm,uint8_t interfaceIndex,UsbPipeType pipeType,UsbPipeDirection pipeDirection)220 static struct UsbPipeInfo *EnumePipe(
221 const struct AcmDevice *acm, uint8_t interfaceIndex, UsbPipeType pipeType, UsbPipeDirection pipeDirection)
222 {
223 struct UsbInterfaceInfo *info = NULL;
224 UsbInterfaceHandle *interfaceHandle = NULL;
225 if (USB_PIPE_TYPE_CONTROL == pipeType) {
226 info = &acm->ctrIface->info;
227 interfaceHandle = acm->ctrDevHandle;
228 } else {
229 info = &acm->iface[interfaceIndex]->info;
230 interfaceHandle = InterfaceIdToHandle(acm, info->interfaceIndex);
231 }
232
233 for (uint8_t i = 0; i <= info->pipeNum; i++) {
234 struct UsbPipeInfo p;
235 int32_t ret = UsbGetPipeInfo(interfaceHandle, info->curAltSetting, i, &p);
236 if (ret < 0) {
237 continue;
238 }
239 if ((p.pipeDirection == pipeDirection) && (p.pipeType == pipeType)) {
240 struct UsbPipeInfo *pi = OsalMemCalloc(sizeof(*pi));
241 if (pi == NULL) {
242 HDF_LOGE("%{public}s: Alloc pipe failed", __func__);
243 return NULL;
244 }
245 p.interfaceId = info->interfaceIndex;
246 *pi = p;
247 return pi;
248 }
249 }
250 return NULL;
251 }
252
GetPipe(const struct AcmDevice * acm,UsbPipeType pipeType,UsbPipeDirection pipeDirection)253 static struct UsbPipeInfo *GetPipe(const struct AcmDevice *acm, UsbPipeType pipeType, UsbPipeDirection pipeDirection)
254 {
255 uint8_t i;
256 if (acm == NULL) {
257 HDF_LOGE("%{public}s: invalid parmas", __func__);
258 return NULL;
259 }
260 for (i = 0; i < acm->interfaceCnt; i++) {
261 struct UsbPipeInfo *p = NULL;
262 if (!acm->iface[i]) {
263 continue;
264 }
265 p = EnumePipe(acm, i, pipeType, pipeDirection);
266 if (p == NULL) {
267 continue;
268 }
269 return p;
270 }
271 return NULL;
272 }
273
SpeedPrint(void)274 static void SpeedPrint(void)
275 {
276 double speed;
277 uint64_t count;
278
279 sigCnt++;
280 count = (uint64_t)sigCnt * TEST_PRINT_TIME;
281 if (count >= TEST_TIME) {
282 g_speedFlag = true;
283 }
284 speed = (g_byteTotal * TEST_FLOAT_COUNT) / (sigCnt * TEST_PRINT_TIME * TEST_BYTE_COUNT * TEST_BYTE_COUNT);
285 printf("\nSpeed:%f MB/s\n", speed);
286 }
287
ShowHelp(const char * name)288 static void ShowHelp(const char *name)
289 {
290 printf(">> usage:\n");
291 printf(">> %s [<busNum> <devAddr>] <ifaceNum> <w>/<r> [printdata]> \n", name);
292 printf("\n");
293 }
294
UsbGetDevInfo(int32_t * const busNum,int32_t * const devNum)295 static void UsbGetDevInfo(int32_t * const busNum, int32_t * const devNum)
296 {
297 struct UsbGetDevicePara paraData;
298 struct usb_device *usbPnpDevice = NULL;
299 paraData.type = USB_PNP_DEVICE_VENDOR_PRODUCT_TYPE;
300 paraData.vendorId = USB_DEVICE_VENDOR_ID;
301 paraData.productId = USB_DEVICE_PRODUCT_ID;
302 usbPnpDevice = UsbPnpNotifyGetUsbDevice(paraData);
303 if (usbPnpDevice == NULL) {
304 HDF_LOGE("%{public}s:%{public}d UsbPnpNotifyGetUsbDevice is null!", __func__, __LINE__);
305 return;
306 }
307 *busNum = (int)usbPnpDevice->address;
308 *devNum = (int)usbPnpDevice->port_no;
309 printf("%s:%d busNum = %d, devNum = %d!\n", __func__, __LINE__, *busNum, *devNum);
310 }
311
UsbSerialOpen(void)312 static int32_t UsbSerialOpen(void)
313 {
314 return HDF_SUCCESS;
315 }
316
UsbSerialClose(void)317 static int32_t UsbSerialClose(void)
318 {
319 if (!g_speedFlag) {
320 g_speedFlag = true;
321 }
322 return HDF_SUCCESS;
323 }
324
UsbSerialSpeedInit(const struct UsbSpeedTest * input,int32_t * ifaceNum)325 static int32_t UsbSerialSpeedInit(const struct UsbSpeedTest *input, int32_t *ifaceNum)
326 {
327 int32_t busNum = 1;
328 int32_t devAddr = 2;
329 if (input == NULL) {
330 return HDF_ERR_INVALID_PARAM;
331 }
332
333 g_speedFlag = false;
334 g_send_count = 0;
335 g_recv_count = 0;
336 g_byteTotal = 0;
337 g_printData = false;
338 g_writeOrRead = TEST_WRITE;
339 sigCnt = 0;
340
341 UsbGetDevInfo(&busNum, &devAddr);
342 if (input->paramNum == TEST_SIX_TYPE) {
343 busNum = input->busNum;
344 devAddr = input->devAddr;
345 *ifaceNum = input->ifaceNum;
346 g_writeOrRead = input->writeOrRead;
347 if (g_writeOrRead == TEST_READ) {
348 g_printData = input->printData;
349 }
350 } else if (input->paramNum == TEST_FIVE_TYPE) {
351 busNum = input->busNum;
352 devAddr = input->devAddr;
353 *ifaceNum = input->ifaceNum;
354 g_writeOrRead = input->writeOrRead;
355 } else if (input->paramNum == TEST_THREE_TYPE) {
356 *ifaceNum = input->ifaceNum;
357 g_writeOrRead = input->writeOrRead;
358 } else {
359 printf("Error: parameter error! \n\n");
360 ShowHelp("speedtest");
361 return HDF_FAILURE;
362 }
363
364 g_acm->busNum = (uint8_t)busNum;
365 g_acm->devAddr = (uint8_t)devAddr;
366 g_acm->interfaceCnt = 1;
367 g_acm->interfaceIndex[0] = *ifaceNum;
368 OsalSemInit(&timeSem, 0);
369
370 return HDF_SUCCESS;
371 }
372
UsbSpeedDdkInit(void)373 static int32_t UsbSpeedDdkInit(void)
374 {
375 uint8_t i;
376 int32_t ret = UsbInitHostSdk(NULL);
377 if (ret != HDF_SUCCESS) {
378 HDF_LOGE("%{public}s:%{public}d UsbInitHostSdk failed", __func__, __LINE__);
379 return HDF_ERR_IO;
380 }
381
382 for (i = 0; i < g_acm->interfaceCnt; i++) {
383 g_acm->iface[i] = GetUsbInterfaceById((const struct AcmDevice *)g_acm, g_acm->interfaceIndex[i]);
384 }
385
386 for (i = 0; i < g_acm->interfaceCnt; i++) {
387 if (g_acm->iface[i]) {
388 g_acm->devHandle[i] = UsbOpenInterface(g_acm->iface[i]);
389 if (g_acm->devHandle[i] == NULL) {
390 HDF_LOGI("%{public}s: UsbOpenInterface null", __func__);
391 }
392 } else {
393 HDF_LOGE("%{public}s:%{public}d g_acm->iface[%{public}hhu] is null.", __func__, __LINE__, i);
394 return HDF_FAILURE;
395 }
396 }
397 if (g_writeOrRead == TEST_WRITE) {
398 g_acm->dataPipe = GetPipe(g_acm, USB_PIPE_TYPE_BULK, USB_PIPE_DIRECTION_OUT);
399 } else {
400 g_acm->dataPipe = GetPipe(g_acm, USB_PIPE_TYPE_BULK, USB_PIPE_DIRECTION_IN);
401 }
402 if (g_acm->dataPipe == NULL) {
403 HDF_LOGE("%{public}s:%{public}d dataPipe is null", __func__, __LINE__);
404 return HDF_FAILURE;
405 }
406
407 g_acm->dataSize = TEST_LENGTH;
408 if (AcmDataBufAlloc(g_acm) < 0) {
409 HDF_LOGE("%{public}s:%{public}d AcmDataBufAlloc failed", __func__, __LINE__);
410 return HDF_FAILURE;
411 }
412
413 return ret;
414 }
415
UsbSpeedRequestHandle(void)416 static int32_t UsbSpeedRequestHandle(void)
417 {
418 for (int32_t i = 0; i < TEST_CYCLE; i++) {
419 struct AcmDb *snd = &(g_acm->db[i]);
420 snd->request = UsbAllocRequest(InterfaceIdToHandle(g_acm, g_acm->dataPipe->interfaceId), 0, g_acm->dataSize);
421 if (snd->request == NULL) {
422 printf("%s:%d snd request fail", __func__, __LINE__);
423 }
424 g_acm->transmitting++;
425 struct UsbRequestParams parmas = {};
426 parmas.interfaceId = g_acm->dataPipe->interfaceId;
427 parmas.pipeAddress = g_acm->dataPipe->pipeAddress;
428 parmas.pipeId = g_acm->dataPipe->pipeId;
429 parmas.callback = AcmTestBulkCallback;
430 parmas.requestType = USB_REQUEST_PARAMS_DATA_TYPE;
431 parmas.timeout = USB_CTRL_SET_TIMEOUT;
432 parmas.dataReq.numIsoPackets = 0;
433 parmas.userData = (void *)snd;
434 parmas.dataReq.length = (int)g_acm->dataSize;
435 parmas.dataReq.buffer = snd->buf;
436 parmas.dataReq.directon = (((uint8_t)g_acm->dataPipe->pipeDirection) >> USB_PIPE_DIR_OFFSET) & 0x1;
437 snd->dbNum = g_acm->transmitting;
438 int32_t rc = UsbFillRequest(snd->request, InterfaceIdToHandle(g_acm, g_acm->dataPipe->interfaceId), &parmas);
439 if (rc != HDF_SUCCESS) {
440 printf("%s:UsbFillRequest failed,ret = %d \n", __func__, rc);
441 return rc;
442 }
443 }
444
445 return HDF_SUCCESS;
446 }
447
UsbSpeedDdkExit(void)448 static void UsbSpeedDdkExit(void)
449 {
450 uint8_t i;
451
452 for (i = 0; i < TEST_CYCLE; i++) {
453 struct AcmDb *snd = &(g_acm->db[i]);
454 UsbCancelRequest(snd->request);
455 UsbFreeRequest(snd->request);
456 }
457 AcmDataBufFree(g_acm);
458 for (i = 0; i < g_acm->interfaceCnt; i++) {
459 UsbCloseInterface(g_acm->devHandle[i], false);
460 UsbReleaseInterface(g_acm->iface[i]);
461 }
462 UsbExitHostSdk(NULL);
463 OsalSemDestroy(&timeSem);
464 g_acm->busy = false;
465 }
466
UsbSerialSpeed(struct HdfSBuf * data)467 static int32_t UsbSerialSpeed(struct HdfSBuf *data)
468 {
469 int32_t ifaceNum = 3;
470 int32_t ret = HDF_SUCCESS;
471 struct UsbSpeedTest *input = NULL;
472 uint32_t size = 0;
473 int32_t i;
474 if (g_acm->busy) {
475 printf("%s: speed test busy\n", __func__);
476 ret = HDF_ERR_IO;
477 goto END;
478 } else {
479 g_acm->busy = true;
480 }
481
482 (void)HdfSbufReadBuffer(data, (const void **)&input, &size);
483 if ((input == NULL) || (size != sizeof(struct UsbSpeedTest))) {
484 printf("%s: sbuf read buffer failed", __func__);
485 ret = HDF_ERR_IO;
486 goto END;
487 }
488
489 ret = UsbSerialSpeedInit(input, &ifaceNum);
490 if (ret != HDF_SUCCESS) {
491 goto END;
492 }
493
494 ret = UsbSpeedDdkInit();
495 if (ret != HDF_SUCCESS) {
496 goto END;
497 }
498
499 ret = UsbSpeedRequestHandle();
500 if (ret != HDF_SUCCESS) {
501 goto END;
502 }
503
504 printf("test SDK API [%s]\n", g_writeOrRead ? "write" : "read");
505
506 for (i = 0; i < TEST_CYCLE; i++) {
507 if (SerialBegin(g_acm) != HDF_SUCCESS) {
508 printf("SerialBegin error!\n");
509 }
510 g_send_count++;
511 }
512
513 OsalSemWait(&timeSem, TEST_TIME);
514 while (!g_speedFlag) {
515 OsalSemWait(&timeSem, TEST_PRINT_TIME * TEST_PRINT_TIME_UINT);
516 SpeedPrint();
517 }
518
519 UsbSpeedDdkExit();
520
521 END:
522 if (ret != HDF_SUCCESS) {
523 printf("please check whether usb drv so is existing or not,like acm, ecm, if not, remove it and test again!\n");
524 }
525 return ret;
526 }
527
AcmDeviceDispatch(struct HdfDeviceIoClient * const client,int32_t cmd,struct HdfSBuf * data,struct HdfSBuf * reply)528 static int32_t AcmDeviceDispatch(
529 struct HdfDeviceIoClient * const client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
530 {
531 (void)reply;
532 if (client == NULL) {
533 HDF_LOGE("%{public}s: client is NULL", __func__);
534 return HDF_ERR_INVALID_OBJECT;
535 }
536
537 if (client->device == NULL) {
538 HDF_LOGE("%{public}s: client->device is NULL", __func__);
539 return HDF_ERR_INVALID_OBJECT;
540 }
541
542 if (client->device->service == NULL) {
543 HDF_LOGE("%{public}s: client->device->service is NULL", __func__);
544 return HDF_ERR_INVALID_OBJECT;
545 }
546
547 g_acm = (struct AcmDevice *)client->device->service;
548
549 switch (cmd) {
550 case USB_SERIAL_OPEN:
551 return UsbSerialOpen();
552 case USB_SERIAL_CLOSE:
553 return UsbSerialClose();
554 case USB_SERIAL_SPEED:
555 return UsbSerialSpeed(data);
556 default:
557 return HDF_ERR_NOT_SUPPORT;
558 }
559
560 return HDF_SUCCESS;
561 }
562
AcmDriverBind(struct HdfDeviceObject * device)563 static int32_t AcmDriverBind(struct HdfDeviceObject *device)
564 {
565 if (device == NULL) {
566 HDF_LOGE("%{public}s: device is null", __func__);
567 return HDF_ERR_INVALID_OBJECT;
568 }
569
570 g_acm = (struct AcmDevice *)OsalMemCalloc(sizeof(*g_acm));
571 if (g_acm == NULL) {
572 HDF_LOGE("%{public}s: Alloc usb acm device failed", __func__);
573 return HDF_FAILURE;
574 }
575
576 g_acm->device = device;
577 device->service = &(g_acm->service);
578 if (g_acm->device && g_acm->device->service) {
579 g_acm->device->service->Dispatch = AcmDeviceDispatch;
580 }
581 return HDF_SUCCESS;
582 }
583
AcmDriverInit(struct HdfDeviceObject * device)584 static int32_t AcmDriverInit(struct HdfDeviceObject *device)
585 {
586 (void)device;
587 return 0;
588 }
589
AcmDriverRelease(struct HdfDeviceObject * device)590 static void AcmDriverRelease(struct HdfDeviceObject *device)
591 {
592 (void)device;
593 return;
594 }
595
596 struct HdfDriverEntry g_usbSdkApiSpeedDriverEntry = {
597 .moduleVersion = 1,
598 .moduleName = "usb_sdkapispeed",
599 .Bind = AcmDriverBind,
600 .Init = AcmDriverInit,
601 .Release = AcmDriverRelease,
602 };
603
604 HDF_INIT(g_usbSdkApiSpeedDriverEntry);
605