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