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