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
43 static unsigned int g_speedFlag = 0;
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
50 static void AcmTestBulkCallback(struct UsbRequest *req);
51 static int32_t SerialBegin(struct AcmDevice * const acm);
52
AcmDbAlloc(struct AcmDevice * const acm)53 static 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
AcmDbIsAvail(struct AcmDevice * const acm)73 static 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
InterfaceIdToHandle(const struct AcmDevice * acm,uint8_t id)82 static 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
AcmStartDb(struct AcmDevice * acm,struct AcmDb * db,struct UsbPipeInfo * pipe)100 static 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
AcmDataBufAlloc(struct AcmDevice * const acm)113 static 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
AcmTestBulkCallback(struct UsbRequest * req)135 static 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
SerialBegin(struct AcmDevice * acm)180 static 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
GetUsbInterfaceById(const struct AcmDevice * acm,uint8_t interfaceIndex)204 static struct UsbInterface *GetUsbInterfaceById(const struct AcmDevice *acm, uint8_t interfaceIndex)
205 {
206 return UsbClaimInterface(acm->session, acm->busNum, acm->devAddr, interfaceIndex);
207 }
208
EnumePipe(const struct AcmDevice * acm,uint8_t interfaceIndex,UsbPipeType pipeType,UsbPipeDirection pipeDirection)209 static 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
GetPipe(const struct AcmDevice * acm,UsbPipeType pipeType,UsbPipeDirection pipeDirection)242 static 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
SignalHandler(int32_t signo)263 static 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
ShowHelp(const char * name)291 static 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
CheckParam(int32_t argc,const char * argv[])298 static 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;
336 END:
337 return acm;
338 }
339
InitUsbDdk(struct AcmDevice * acm)340 static 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 }
377 END:
378 return ret;
379 }
380
FillRequest(struct AcmDevice * const acm)381 static 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
main(int32_t argc,char * argv[])414 int32_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 }
458 END:
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