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