1 /*
2 * Copyright (c) 2020-2022 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "gpio_test.h"
10 #include "gpio_if.h"
11 #include "hdf_base.h"
12 #include "hdf_io_service_if.h"
13 #include "hdf_log.h"
14 #include "osal_irq.h"
15 #include "osal_time.h"
16 #include "securec.h"
17
18 #define HDF_LOG_TAG gpio_test
19
20 #define GPIO_TEST_IRQ_TIMEOUT 1000
21 #define GPIO_TEST_IRQ_DELAY 200
22
GpioTestGetConfig(struct GpioTestConfig * config)23 static int32_t GpioTestGetConfig(struct GpioTestConfig *config)
24 {
25 int32_t ret;
26 struct HdfSBuf *reply = NULL;
27 struct HdfIoService *service = NULL;
28 const void *buf = NULL;
29 uint32_t len;
30
31 HDF_LOGD("%s: enter!", __func__);
32 service = HdfIoServiceBind("GPIO_TEST");
33 if (service == NULL) {
34 HDF_LOGE("%s: failed to bind gpio test server!", __func__);
35 return HDF_ERR_NOT_SUPPORT;
36 }
37
38 reply = HdfSbufObtain(sizeof(*config) + sizeof(uint64_t));
39 if (reply == NULL) {
40 HDF_LOGE("%s: failed to obtain reply!", __func__);
41 HdfIoServiceRecycle(service);
42 return HDF_ERR_MALLOC_FAIL;
43 }
44
45 ret = service->dispatcher->Dispatch(&service->object, 0, NULL, reply);
46 if (ret != HDF_SUCCESS) {
47 HDF_LOGE("%s: remote dispatch failed:%d!", __func__, ret);
48 HdfIoServiceRecycle(service);
49 HdfSbufRecycle(reply);
50 return ret;
51 }
52
53 if (!HdfSbufReadBuffer(reply, &buf, &len)) {
54 HDF_LOGE("%s: failed to read buf!", __func__);
55 HdfIoServiceRecycle(service);
56 HdfSbufRecycle(reply);
57 return HDF_ERR_IO;
58 }
59
60 if (len != sizeof(*config)) {
61 HDF_LOGE("%s: config size:%u, but read size:%u!", __func__, sizeof(*config), len);
62 HdfIoServiceRecycle(service);
63 HdfSbufRecycle(reply);
64 return HDF_ERR_IO;
65 }
66
67 if (memcpy_s(config, sizeof(*config), buf, sizeof(*config)) != EOK) {
68 HDF_LOGE("%s: failed to memcpy buf!", __func__);
69 HdfIoServiceRecycle(service);
70 HdfSbufRecycle(reply);
71 return HDF_ERR_IO;
72 }
73
74 HdfSbufRecycle(reply);
75 HDF_LOGD("%s: exit!", __func__);
76 HdfIoServiceRecycle(service);
77 return HDF_SUCCESS;
78 }
79
GpioTesterGet(void)80 static struct GpioTester *GpioTesterGet(void)
81 {
82 int32_t ret;
83 static struct GpioTester tester;
84 static struct GpioTester *pTester = NULL;
85
86 if (pTester != NULL) {
87 return pTester;
88 }
89
90 ret = GpioTestGetConfig(&tester.cfg);
91 if (ret != HDF_SUCCESS) {
92 HDF_LOGE("%s: failed to get config:%d!", __func__, ret);
93 return NULL;
94 }
95 HDF_LOGI("%s: gpio=%u, gpioIrq=%u, testUserApi=%u, gpioTestTwo=%u, testNameOne=%s, testNameTwo=%s!", __func__,
96 tester.cfg.gpio, tester.cfg.gpioIrq, tester.cfg.testUserApi, tester.cfg.gpioTestTwo, tester.cfg.testNameOne,
97 tester.cfg.testNameTwo);
98
99 pTester = &tester;
100 return pTester;
101 }
102
GpioTestSetUp(void)103 static int32_t GpioTestSetUp(void)
104 {
105 int32_t ret;
106 struct GpioTester *tester = NULL;
107
108 tester = GpioTesterGet();
109 if (tester == NULL) {
110 HDF_LOGE("%s: failed to get tester!", __func__);
111 return HDF_ERR_INVALID_OBJECT;
112 }
113
114 ret = GpioGetDir(tester->cfg.gpio, &tester->oldDir);
115 if (ret != HDF_SUCCESS) {
116 HDF_LOGE("%s: failed to get old dir, ret:%d!", __func__, ret);
117 return ret;
118 }
119 ret = GpioRead(tester->cfg.gpio, &tester->oldVal);
120 if (ret != HDF_SUCCESS) {
121 HDF_LOGE("%s: failed to read old val, ret:%d!", __func__, ret);
122 return ret;
123 }
124
125 tester->fails = 0;
126 tester->irqCnt = 0;
127 tester->irqTimeout = GPIO_TEST_IRQ_TIMEOUT;
128 return HDF_SUCCESS;
129 }
130
GpioTestTearDown(void)131 static int32_t GpioTestTearDown(void)
132 {
133 int ret;
134 struct GpioTester *tester = NULL;
135
136 tester = GpioTesterGet();
137 if (tester == NULL) {
138 HDF_LOGE("%s: failed to get tester!", __func__);
139 return HDF_ERR_INVALID_OBJECT;
140 }
141
142 ret = GpioSetDir(tester->cfg.gpio, tester->oldDir);
143 if (ret != HDF_SUCCESS) {
144 HDF_LOGE("%s: failed to set old dir, ret:%d!", __func__, ret);
145 return ret;
146 }
147 if (tester->oldDir == GPIO_DIR_IN) {
148 return HDF_SUCCESS;
149 }
150 ret = GpioWrite(tester->cfg.gpio, tester->oldVal);
151 if (ret != HDF_SUCCESS) {
152 HDF_LOGE("%s: failed to write old val, ret:%d!", __func__, ret);
153 return ret;
154 }
155
156 return HDF_SUCCESS;
157 }
158
GpioTestSetGetDir(void)159 static int32_t GpioTestSetGetDir(void)
160 {
161 int32_t ret;
162 uint16_t dirSet;
163 uint16_t dirGet;
164 struct GpioTester *tester = NULL;
165
166 tester = GpioTesterGet();
167 if (tester == NULL) {
168 HDF_LOGE("%s: failde to get tester!", __func__);
169 return HDF_ERR_INVALID_OBJECT;
170 }
171
172 dirSet = GPIO_DIR_OUT;
173 dirGet = GPIO_DIR_IN;
174
175 ret = GpioSetDir(tester->cfg.gpio, dirSet);
176 if (ret != HDF_SUCCESS) {
177 HDF_LOGE("%s: failed to set dir, ret:%d!", __func__, ret);
178 return ret;
179 }
180 ret = GpioGetDir(tester->cfg.gpio, &dirGet);
181 if (ret != HDF_SUCCESS) {
182 HDF_LOGE("%s: failed to get dir, ret:%d!", __func__, ret);
183 return ret;
184 }
185 if (dirSet != dirGet) {
186 HDF_LOGE("%s: set dir:%u, but get:%u!", __func__, dirSet, dirGet);
187 return HDF_FAILURE;
188 }
189 /* change the value and test one more time */
190 dirSet = GPIO_DIR_IN;
191 dirGet = GPIO_DIR_OUT;
192 ret = GpioSetDir(tester->cfg.gpio, dirSet);
193 if (ret != HDF_SUCCESS) {
194 HDF_LOGE("%s: failed to set dir, ret:%d!", __func__, ret);
195 return ret;
196 }
197 ret = GpioGetDir(tester->cfg.gpio, &dirGet);
198 if (ret != HDF_SUCCESS) {
199 HDF_LOGE("%s: failde to get dir, ret:%d!", __func__, ret);
200 return ret;
201 }
202 if (dirSet != dirGet) {
203 HDF_LOGE("%s: set dir:%hu, but get:%hu!", __func__, dirSet, dirGet);
204 return HDF_FAILURE;
205 }
206 return HDF_SUCCESS;
207 }
208
GpioTestWriteRead(void)209 static int32_t GpioTestWriteRead(void)
210 {
211 int32_t ret;
212 uint16_t valWrite;
213 uint16_t valRead;
214 struct GpioTester *tester = NULL;
215
216 tester = GpioTesterGet();
217 if (tester == NULL) {
218 HDF_LOGE("%s: failed to get tester!", __func__);
219 return HDF_ERR_INVALID_OBJECT;
220 }
221
222 ret = GpioSetDir(tester->cfg.gpio, GPIO_DIR_OUT);
223 if (ret != HDF_SUCCESS) {
224 HDF_LOGE("%s: failed to set dir, ret:%d!", __func__, ret);
225 return ret;
226 }
227 valWrite = GPIO_VAL_LOW;
228 valRead = GPIO_VAL_HIGH;
229
230 ret = GpioWrite(tester->cfg.gpio, valWrite);
231 if (ret != HDF_SUCCESS) {
232 HDF_LOGE("%s: failed to write val:%hu, ret:%d!", __func__, valWrite, ret);
233 return ret;
234 }
235 ret = GpioRead(tester->cfg.gpio, &valRead);
236 if (ret != HDF_SUCCESS) {
237 HDF_LOGE("%s: failed to read, ret:%d!", __func__, ret);
238 return ret;
239 }
240 if (valWrite != valRead) {
241 HDF_LOGE("%s: write:%u, but get:%u!", __func__, valWrite, valRead);
242 return HDF_FAILURE;
243 }
244 /* change the value and test one more time */
245 valWrite = GPIO_VAL_HIGH;
246 valRead = GPIO_VAL_LOW;
247 ret = GpioWrite(tester->cfg.gpio, valWrite);
248 if (ret != HDF_SUCCESS) {
249 HDF_LOGE("%s: failed towrite val:%u, ret:%d!", __func__, valWrite, ret);
250 return ret;
251 }
252 ret = GpioRead(tester->cfg.gpio, &valRead);
253 if (ret != HDF_SUCCESS) {
254 HDF_LOGE("%s: failed to read, ret:%d!", __func__, ret);
255 return ret;
256 }
257 if (valWrite != valRead) {
258 HDF_LOGE("%s: write:%u, but get:%u!", __func__, valWrite, valRead);
259 return HDF_FAILURE;
260 }
261 return HDF_SUCCESS;
262 }
263
GpioTestIrqHandler(uint16_t gpio,void * data)264 static int32_t GpioTestIrqHandler(uint16_t gpio, void *data)
265 {
266 struct GpioTester *tester = (struct GpioTester *)data;
267
268 HDF_LOGE("%s: >>>>>>>>>>>>>>>>>>>>>enter gpio:%hu<<<<<<<<<<<<<<<<<<<<<<", __func__, gpio);
269 if (tester != NULL) {
270 tester->irqCnt++;
271 return GpioDisableIrq(gpio);
272 }
273 return HDF_FAILURE;
274 }
275
GpioTestHelperInversePin(uint16_t gpio,uint16_t mode)276 static inline void GpioTestHelperInversePin(uint16_t gpio, uint16_t mode)
277 {
278 uint16_t dir = 0;
279 uint16_t valRead = 0;
280
281 (void)GpioRead(gpio, &valRead);
282 (void)GpioWrite(gpio, (valRead == GPIO_VAL_LOW) ? GPIO_VAL_HIGH : GPIO_VAL_LOW);
283 (void)GpioRead(gpio, &valRead);
284 (void)GpioGetDir(gpio, &dir);
285 HDF_LOGE("%s, gpio:%u, val:%u, dir:%u, mode:%x!", __func__, gpio, valRead, dir, mode);
286 }
287
GpioTestIrqSharedFunc(struct GpioTester * tester,uint16_t mode,bool inverse)288 static int32_t GpioTestIrqSharedFunc(struct GpioTester *tester, uint16_t mode, bool inverse)
289 {
290 int32_t ret;
291 uint32_t timeout;
292
293 HDF_LOGE("%s: mark gona set irq ...", __func__);
294 ret = GpioSetIrq(tester->cfg.gpioIrq, mode, GpioTestIrqHandler, (void *)tester);
295 if (ret != HDF_SUCCESS) {
296 HDF_LOGE("%s: failed to set irq, ret:%d!", __func__, ret);
297 return ret;
298 }
299 HDF_LOGE("%s: mark gona enable irq ...", __func__);
300 ret = GpioEnableIrq(tester->cfg.gpioIrq);
301 if (ret != HDF_SUCCESS) {
302 HDF_LOGE("%s: failed to enable irq, ret:%d!", __func__, ret);
303 (void)GpioUnsetIrq(tester->cfg.gpioIrq, tester);
304 return ret;
305 }
306
307 HDF_LOGE("%s: mark gona inverse irq ...", __func__);
308 for (timeout = 0; tester->irqCnt == 0 && timeout <= tester->irqTimeout;
309 timeout += GPIO_TEST_IRQ_DELAY) {
310 if (inverse) {
311 // maybe can make an inverse ...
312 GpioTestHelperInversePin(tester->cfg.gpioIrq, mode);
313 }
314 OsalMSleep(GPIO_TEST_IRQ_DELAY);
315 }
316 (void)GpioUnsetIrq(tester->cfg.gpioIrq, tester);
317
318 #if defined(_LINUX_USER_) || defined(__KERNEL__)
319 if (inverse) {
320 HDF_LOGI("%s: do not judge edge trigger!", __func__);
321 return HDF_SUCCESS;
322 }
323 #endif
324 if (tester->irqCnt == 0) {
325 HDF_LOGE("%s: failed to set mode:%x on %u!", __func__, mode, tester->cfg.gpioIrq);
326 return HDF_FAILURE;
327 }
328 return HDF_SUCCESS;
329 }
330
GpioTestIrqLevel(void)331 static int32_t GpioTestIrqLevel(void)
332 {
333 return HDF_SUCCESS;
334 }
335
GpioTestIrqEdge(void)336 static int32_t GpioTestIrqEdge(void)
337 {
338 uint16_t mode;
339 struct GpioTester *tester = NULL;
340
341 tester = GpioTesterGet();
342 if (tester == NULL) {
343 HDF_LOGE("%s: failed to get tester!", __func__);
344 return HDF_ERR_INVALID_OBJECT;
345 }
346
347 /* set dir to out for self trigger on liteos */
348 #if defined(_LINUX_USER_) || defined(__KERNEL__)
349 (void)GpioSetDir(tester->cfg.gpioIrq, GPIO_DIR_IN);
350 #else
351 (void)GpioSetDir(tester->cfg.gpioIrq, GPIO_DIR_OUT);
352 #endif
353 mode = GPIO_IRQ_TRIGGER_FALLING | GPIO_IRQ_TRIGGER_RISING;
354 return GpioTestIrqSharedFunc(tester, mode, true);
355 }
356
GpioTestIrqThread(void)357 static int32_t GpioTestIrqThread(void)
358 {
359 uint16_t mode;
360 struct GpioTester *tester = NULL;
361
362 tester = GpioTesterGet();
363 if (tester == NULL) {
364 HDF_LOGE("%s: failed to get tester!", __func__);
365 return HDF_ERR_INVALID_OBJECT;
366 }
367
368 /* set dir to out for self trigger on liteos */
369 #if defined(_LINUX_USER_) || defined(__KERNEL__)
370 (void)GpioSetDir(tester->cfg.gpioIrq, GPIO_DIR_IN);
371 #else
372 (void)GpioSetDir(tester->cfg.gpioIrq, GPIO_DIR_OUT);
373 #endif
374 mode = GPIO_IRQ_TRIGGER_FALLING | GPIO_IRQ_TRIGGER_RISING | GPIO_IRQ_USING_THREAD;
375 return GpioTestIrqSharedFunc(tester, mode, true);
376 }
377
GpioTestGetNumByName(void)378 static int32_t GpioTestGetNumByName(void)
379 {
380 int32_t ret;
381 struct GpioTester *tester = NULL;
382
383 tester = GpioTesterGet();
384 if (tester == NULL) {
385 HDF_LOGE("%s: failed to get tester!", __func__);
386 return HDF_ERR_INVALID_OBJECT;
387 }
388
389 ret = GpioGetByName(tester->cfg.testNameOne);
390 if (ret < 0) {
391 HDF_LOGE("%s: name:%s failed to get gpio global number, ret:%d!", __func__, tester->cfg.testNameOne, ret);
392 return ret;
393 }
394
395 if (ret != tester->cfg.gpio) {
396 HDF_LOGE("%s: gpio number are different. name:%s get gpio global number:%hu but gpio actual number:%hu!",
397 __func__, tester->cfg.testNameOne, (uint16_t)ret, tester->cfg.gpio);
398 return HDF_FAILURE;
399 }
400
401 ret = GpioGetByName(tester->cfg.testNameTwo);
402 if (ret < 0) {
403 HDF_LOGE("%s: name:%s failed to get gpio global number, ret:%d!", __func__, tester->cfg.testNameTwo, ret);
404 return ret;
405 }
406
407 if (ret != tester->cfg.gpioTestTwo) {
408 HDF_LOGE("%s: gpio number are different. name:%s get gpio global number:%hu but gpio actual number :%hu!",
409 __func__, tester->cfg.testNameTwo, (uint16_t)ret, tester->cfg.gpioTestTwo);
410 return HDF_FAILURE;
411 }
412
413 return HDF_SUCCESS;
414 }
415
GpioTestReliability(void)416 static int32_t GpioTestReliability(void)
417 {
418 uint16_t val = 0;
419 struct GpioTester *tester = NULL;
420
421 tester = GpioTesterGet();
422 if (tester == NULL) {
423 HDF_LOGE("%s: failed to get tester!", __func__);
424 return HDF_ERR_INVALID_OBJECT;
425 }
426
427 (void)GpioGetByName(NULL); /* invalid gpio name */
428 (void)GpioWrite(-1, val); /* invalid gpio number */
429 (void)GpioWrite(tester->cfg.gpio, -1); /* invalid gpio value */
430
431 (void)GpioRead(-1, &val); /* invalid gpio number */
432 (void)GpioRead(tester->cfg.gpio, NULL); /* invalid pointer */
433
434 (void)GpioSetDir(-1, val); /* invalid gpio number */
435 (void)GpioSetDir(tester->cfg.gpio, -1); /* invalid value */
436
437 (void)GpioGetDir(-1, &val); /* invalid gpio number */
438 (void)GpioGetDir(tester->cfg.gpio, NULL); /* invalid pointer */
439
440 /* invalid gpio number */
441 (void)GpioSetIrq(-1, OSAL_IRQF_TRIGGER_RISING, GpioTestIrqHandler, (void *)tester);
442 /* invalid irq handler */
443 (void)GpioSetIrq(tester->cfg.gpioIrq, OSAL_IRQF_TRIGGER_RISING, NULL, (void *)tester);
444
445 (void)GpioUnsetIrq(-1, NULL); /* invalid gpio number */
446
447 (void)GpioEnableIrq(-1); /* invalid gpio number */
448
449 (void)GpioDisableIrq(-1); /* invalid gpio number */
450
451 return HDF_SUCCESS;
452 }
453
GpioIfPerformanceTest(void)454 static int32_t GpioIfPerformanceTest(void)
455 {
456 #ifdef __LITEOS__
457 return HDF_SUCCESS;
458 #endif
459 uint16_t val;
460 uint64_t startMs;
461 uint64_t endMs;
462 uint64_t useTime; // ms
463 struct GpioTester *tester = NULL;
464
465 tester = GpioTesterGet();
466 if (tester == NULL) {
467 HDF_LOGE("%s: failed to get tester!", __func__);
468 return HDF_ERR_INVALID_OBJECT;
469 }
470
471 startMs = OsalGetSysTimeMs();
472 GpioRead(tester->cfg.gpio, &val);
473 endMs = OsalGetSysTimeMs();
474
475 useTime = endMs - startMs;
476 HDF_LOGI("----->interface performance test:[start - end] < 1ms[%s]\r\n", useTime < 1 ? "yes" : "no");
477 return HDF_SUCCESS;
478 }
479
480 struct GpioTestEntry {
481 int cmd;
482 int32_t (*func)(void);
483 const char *name;
484 };
485
486 static struct GpioTestEntry g_entry[] = {
487 { GPIO_TEST_SET_GET_DIR, GpioTestSetGetDir, "GpioTestSetGetDir" },
488 { GPIO_TEST_WRITE_READ, GpioTestWriteRead, "GpioTestWriteRead" },
489 { GPIO_TEST_IRQ_LEVEL, GpioTestIrqLevel, "GpioTestIrqLevel" },
490 { GPIO_TEST_IRQ_EDGE, GpioTestIrqEdge, "GpioTestIrqEdge" },
491 { GPIO_TEST_IRQ_THREAD, GpioTestIrqThread, "GpioTestIrqThread" },
492 { GPIO_TEST_GET_NUM_BY_NAME, GpioTestGetNumByName, "GpioTestGetNumByName" },
493 { GPIO_TEST_RELIABILITY, GpioTestReliability, "GpioTestReliability" },
494 { GPIO_TEST_PERFORMANCE, GpioIfPerformanceTest, "GpioIfPerformanceTest" },
495 };
496
GpioTestExecute(int cmd)497 int32_t GpioTestExecute(int cmd)
498 {
499 uint32_t i;
500 int32_t ret = HDF_ERR_NOT_SUPPORT;
501
502 #if defined(_LINUX_USER_) || defined(__USER__)
503 struct GpioTester *tester = GpioTesterGet();
504 if (tester == NULL) {
505 HDF_LOGI("%s: tester is NULL!", __func__);
506 return HDF_SUCCESS;
507 }
508 if (tester->cfg.testUserApi == 0) {
509 HDF_LOGI("%s: do not test user api!", __func__);
510 return HDF_SUCCESS;
511 }
512 #endif
513
514 for (i = 0; i < sizeof(g_entry) / sizeof(g_entry[0]); i++) {
515 if (g_entry[i].cmd != cmd || g_entry[i].func == NULL) {
516 continue;
517 }
518 ret = GpioTestSetUp();
519 if (ret != HDF_SUCCESS) {
520 HDF_LOGE("%s: failed to setup!", __func__);
521 return ret;
522 }
523
524 ret = g_entry[i].func();
525
526 (void)GpioTestTearDown();
527 break;
528 }
529
530 if (ret == HDF_ERR_NOT_SUPPORT) {
531 HDF_LOGE("%s: cmd:%d not supportted!", __func__, cmd);
532 }
533
534 HDF_LOGI("[%s][======cmd:%d====ret:%d======]", __func__, cmd, ret);
535 return ret;
536 }
537
GpioTestExecuteAll(void)538 void GpioTestExecuteAll(void)
539 {
540 int32_t i;
541 int32_t ret;
542 int32_t fails = 0;
543
544 for (i = 0; i < GPIO_TEST_MAX; i++) {
545 ret = GpioTestExecute(i);
546 fails += (ret != HDF_SUCCESS) ? 1 : 0;
547 }
548
549 HDF_LOGE("%s: **********PASS:%d FAIL:%d************\n\n",
550 __func__, GPIO_TEST_MAX - fails, fails);
551 }
552