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