1 /*
2 * Copyright (c) 2020-2023 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("GpioTestGetConfig: enter!");
32 service = HdfIoServiceBind("GPIO_TEST");
33 if (service == NULL) {
34 HDF_LOGE("GpioTestGetConfig: fail to bind gpio test server!");
35 return HDF_ERR_NOT_SUPPORT;
36 }
37
38 reply = HdfSbufObtain(sizeof(*config) + sizeof(uint64_t));
39 if (reply == NULL) {
40 HDF_LOGE("GpioTestGetConfig: fail to obtain reply!");
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("GpioTestGetConfig: remote dispatch fail, ret: %d!", ret);
48 HdfIoServiceRecycle(service);
49 HdfSbufRecycle(reply);
50 return ret;
51 }
52
53 if (!HdfSbufReadBuffer(reply, &buf, &len)) {
54 HDF_LOGE("GpioTestGetConfig: fail to read buf!");
55 HdfIoServiceRecycle(service);
56 HdfSbufRecycle(reply);
57 return HDF_ERR_IO;
58 }
59
60 if (len != sizeof(*config)) {
61 HDF_LOGE("GpioTestGetConfig: config size:%zu, but read size:%u!", 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("GpioTestGetConfig: fail to memcpy buf!");
69 HdfIoServiceRecycle(service);
70 HdfSbufRecycle(reply);
71 return HDF_ERR_IO;
72 }
73
74 HdfSbufRecycle(reply);
75 HDF_LOGD("GpioTestGetConfig: exit!");
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("GpioTesterGet: fail to get config, ret: %d!", ret);
93 return NULL;
94 }
95 HDF_LOGI("GpioTesterGet: gpio=%u, gpioIrq=%u, testUserApi=%u, gpioTestTwo=%u, testNameOne=%s, testNameTwo=%s!",
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("GpioTestSetUp: fail to get tester!");
111 return HDF_ERR_INVALID_OBJECT;
112 }
113
114 ret = GpioGetDir(tester->cfg.gpio, &tester->oldDir);
115 if (ret != HDF_SUCCESS) {
116 HDF_LOGE("GpioTestSetUp: fail to get old dir, ret: %d!", ret);
117 return ret;
118 }
119 ret = GpioRead(tester->cfg.gpio, &tester->oldVal);
120 if (ret != HDF_SUCCESS) {
121 HDF_LOGE("GpioTestSetUp: fail to read old val, ret: %d!", 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("GpioTestTearDown: fail to get tester!");
139 return HDF_ERR_INVALID_OBJECT;
140 }
141
142 ret = GpioSetDir(tester->cfg.gpio, tester->oldDir);
143 if (ret != HDF_SUCCESS) {
144 HDF_LOGE("GpioTestTearDown: fail to set old dir, ret: %d!", 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("GpioTestTearDown: fail to write old val, ret: %d!", 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("GpioTestSetGetDir: fail to get tester!");
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("GpioTestSetGetDir: fail to set dir, ret: %d!", ret);
178 return ret;
179 }
180 ret = GpioGetDir(tester->cfg.gpio, &dirGet);
181 if (ret != HDF_SUCCESS) {
182 HDF_LOGE("GpioTestSetGetDir: fail to get dir, ret: %d!", ret);
183 return ret;
184 }
185 if (dirSet != dirGet) {
186 HDF_LOGE("GpioTestSetGetDir: set dir:%u, but get:%u!", 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("GpioTestSetGetDir: fail to set dir, ret: %d!", ret);
195 return ret;
196 }
197 ret = GpioGetDir(tester->cfg.gpio, &dirGet);
198 if (ret != HDF_SUCCESS) {
199 HDF_LOGE("GpioTestSetGetDir: fail to get dir, ret: %d!", ret);
200 return ret;
201 }
202 if (dirSet != dirGet) {
203 HDF_LOGE("GpioTestSetGetDir: set dir:%hu, but get:%hu!", 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("GpioTestWriteRead: fail to get tester!");
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("GpioTestWriteRead: fail to set dir, ret: %d!", 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("GpioTestWriteRead: failed to write val:%hu, ret: %d!", valWrite, ret);
233 return ret;
234 }
235 ret = GpioRead(tester->cfg.gpio, &valRead);
236 if (ret != HDF_SUCCESS) {
237 HDF_LOGE("GpioTestWriteRead: fail to read, ret: %d!", ret);
238 return ret;
239 }
240 if (valWrite != valRead) {
241 HDF_LOGE("GpioTestWriteRead: write:%u, but get:%u!", 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("GpioTestWriteRead: fail towrite val:%u, ret: %d!", valWrite, ret);
250 return ret;
251 }
252 ret = GpioRead(tester->cfg.gpio, &valRead);
253 if (ret != HDF_SUCCESS) {
254 HDF_LOGE("GpioTestWriteRead: fail to read, ret: %d!", ret);
255 return ret;
256 }
257 if (valWrite != valRead) {
258 HDF_LOGE("GpioTestWriteRead: write:%u, but get:%u!", 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("GpioTestIrqHandler: >>>>>>>>>>>>>>>>>>>>>enter gpio:%hu<<<<<<<<<<<<<<<<<<<<<<", 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("GpioTestHelperInversePin: gpio:%u, val:%u, dir:%u, mode:%x!", 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_LOGD("GpioTestIrqSharedFunc: mark gona set irq ...");
294 ret = GpioSetIrq(tester->cfg.gpioIrq, mode, GpioTestIrqHandler, (void *)tester);
295 if (ret != HDF_SUCCESS) {
296 HDF_LOGE("GpioTestIrqSharedFunc: fail to set irq, ret:%d!", ret);
297 return ret;
298 }
299 HDF_LOGD("GpioTestIrqSharedFunc: mark gona enable irq ...");
300 ret = GpioEnableIrq(tester->cfg.gpioIrq);
301 if (ret != HDF_SUCCESS) {
302 HDF_LOGE("GpioTestIrqSharedFunc: fail to enable irq, ret: %d!", ret);
303 (void)GpioUnsetIrq(tester->cfg.gpioIrq, tester);
304 return ret;
305 }
306
307 HDF_LOGD("GpioTestIrqSharedFunc: mark gona inverse irq ...");
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("GpioTestIrqSharedFunc: do not judge edge trigger!");
321 return HDF_SUCCESS;
322 }
323 #endif
324 if (tester->irqCnt == 0) {
325 HDF_LOGE("GpioTestIrqSharedFunc: fail to set mode:%x on %u!", 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("GpioTestIrqEdge: fail to get tester!");
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("GpioTestIrqThread: fail to get tester!");
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("GpioTestGetNumByName: fail to get tester!");
386 return HDF_ERR_INVALID_OBJECT;
387 }
388
389 ret = GpioGetByName(tester->cfg.testNameOne);
390 if (ret < 0) {
391 HDF_LOGE("GpioTestGetNumByName: name:%s fail to get gpio global number, ret:%d!",
392 tester->cfg.testNameOne, ret);
393 return ret;
394 }
395
396 if (ret != tester->cfg.gpio) {
397 HDF_LOGE("GpioTestGetNumByName: gpio number are different. \
398 name:%s get gpio global number:%hu but gpio actual number:%hu!",
399 tester->cfg.testNameOne, (uint16_t)ret, tester->cfg.gpio);
400 return HDF_FAILURE;
401 }
402
403 ret = GpioGetByName(tester->cfg.testNameTwo);
404 if (ret < 0) {
405 HDF_LOGE("GpioTestGetNumByName: name:%s fail to get gpio global number, ret:%d!",
406 tester->cfg.testNameTwo, ret);
407 return ret;
408 }
409
410 if (ret != tester->cfg.gpioTestTwo) {
411 HDF_LOGE("GpioTestGetNumByName: gpio number are different. \
412 name:%s get gpio global number:%hu but gpio actual number :%hu!",
413 tester->cfg.testNameTwo, (uint16_t)ret, tester->cfg.gpioTestTwo);
414 return HDF_FAILURE;
415 }
416
417 return HDF_SUCCESS;
418 }
419
GpioTestReliability(void)420 static int32_t GpioTestReliability(void)
421 {
422 uint16_t val = 0;
423 struct GpioTester *tester = NULL;
424
425 tester = GpioTesterGet();
426 if (tester == NULL) {
427 HDF_LOGE("GpioTestReliability: fail to get tester!");
428 return HDF_ERR_INVALID_OBJECT;
429 }
430
431 (void)GpioGetByName(NULL); /* invalid gpio name */
432 (void)GpioWrite(-1, val); /* invalid gpio number */
433 (void)GpioWrite(tester->cfg.gpio, -1); /* invalid gpio value */
434
435 (void)GpioRead(-1, &val); /* invalid gpio number */
436 (void)GpioRead(tester->cfg.gpio, NULL); /* invalid pointer */
437
438 (void)GpioSetDir(-1, val); /* invalid gpio number */
439 (void)GpioSetDir(tester->cfg.gpio, -1); /* invalid value */
440
441 (void)GpioGetDir(-1, &val); /* invalid gpio number */
442 (void)GpioGetDir(tester->cfg.gpio, NULL); /* invalid pointer */
443
444 /* invalid gpio number */
445 (void)GpioSetIrq(-1, OSAL_IRQF_TRIGGER_RISING, GpioTestIrqHandler, (void *)tester);
446 /* invalid irq handler */
447 (void)GpioSetIrq(tester->cfg.gpioIrq, OSAL_IRQF_TRIGGER_RISING, NULL, (void *)tester);
448
449 (void)GpioUnsetIrq(-1, NULL); /* invalid gpio number */
450
451 (void)GpioEnableIrq(-1); /* invalid gpio number */
452
453 (void)GpioDisableIrq(-1); /* invalid gpio number */
454
455 return HDF_SUCCESS;
456 }
457
GpioIfPerformanceTest(void)458 static int32_t GpioIfPerformanceTest(void)
459 {
460 #ifdef __LITEOS__
461 return HDF_SUCCESS;
462 #endif
463 uint16_t val;
464 uint64_t startMs;
465 uint64_t endMs;
466 uint64_t useTime; // ms
467 struct GpioTester *tester = NULL;
468
469 tester = GpioTesterGet();
470 if (tester == NULL) {
471 HDF_LOGE("GpioIfPerformanceTest: fail to get tester!");
472 return HDF_ERR_INVALID_OBJECT;
473 }
474
475 startMs = OsalGetSysTimeMs();
476 GpioRead(tester->cfg.gpio, &val);
477 endMs = OsalGetSysTimeMs();
478
479 useTime = endMs - startMs;
480 HDF_LOGI("GpioIfPerformanceTest: ----->interface performance test:[start - end] < 1ms[%s]\r\n",
481 useTime < 1 ? "yes" : "no");
482 return HDF_SUCCESS;
483 }
484
485 struct GpioTestEntry {
486 int cmd;
487 int32_t (*func)(void);
488 const char *name;
489 };
490
491 static struct GpioTestEntry g_entry[] = {
492 { GPIO_TEST_SET_GET_DIR, GpioTestSetGetDir, "GpioTestSetGetDir" },
493 { GPIO_TEST_WRITE_READ, GpioTestWriteRead, "GpioTestWriteRead" },
494 { GPIO_TEST_IRQ_LEVEL, GpioTestIrqLevel, "GpioTestIrqLevel" },
495 { GPIO_TEST_IRQ_EDGE, GpioTestIrqEdge, "GpioTestIrqEdge" },
496 { GPIO_TEST_IRQ_THREAD, GpioTestIrqThread, "GpioTestIrqThread" },
497 { GPIO_TEST_GET_NUM_BY_NAME, GpioTestGetNumByName, "GpioTestGetNumByName" },
498 { GPIO_TEST_RELIABILITY, GpioTestReliability, "GpioTestReliability" },
499 { GPIO_TEST_PERFORMANCE, GpioIfPerformanceTest, "GpioIfPerformanceTest" },
500 };
501
GpioTestExecute(int cmd)502 int32_t GpioTestExecute(int cmd)
503 {
504 uint32_t i;
505 int32_t ret = HDF_ERR_NOT_SUPPORT;
506
507 #if defined(_LINUX_USER_) || defined(__USER__)
508 struct GpioTester *tester = GpioTesterGet();
509 if (tester == NULL) {
510 HDF_LOGI("GpioTestExecute: tester is null!");
511 return HDF_SUCCESS;
512 }
513 if (tester->cfg.testUserApi == 0) {
514 HDF_LOGI("GpioTestExecute: do not test user api!");
515 return HDF_SUCCESS;
516 }
517 #endif
518
519 for (i = 0; i < sizeof(g_entry) / sizeof(g_entry[0]); i++) {
520 if (g_entry[i].cmd != cmd || g_entry[i].func == NULL) {
521 continue;
522 }
523 ret = GpioTestSetUp();
524 if (ret != HDF_SUCCESS) {
525 HDF_LOGE("GpioTestExecute: fail to setup!");
526 return ret;
527 }
528
529 ret = g_entry[i].func();
530
531 (void)GpioTestTearDown();
532 break;
533 }
534
535 if (ret == HDF_ERR_NOT_SUPPORT) {
536 HDF_LOGE("GpioTestExecute: cmd:%d is not support!", cmd);
537 }
538
539 HDF_LOGI("[GpioTestExecute][======cmd:%d====ret:%d======]", cmd, ret);
540 return ret;
541 }
542
GpioTestExecuteAll(void)543 void GpioTestExecuteAll(void)
544 {
545 int32_t i;
546 int32_t ret;
547 int32_t fails = 0;
548
549 for (i = 0; i < GPIO_TEST_MAX; i++) {
550 ret = GpioTestExecute(i);
551 fails += (ret != HDF_SUCCESS) ? 1 : 0;
552 }
553
554 HDF_LOGE("GpioTestExecuteAll: **********PASS:%d FAIL:%d************\n\n",
555 GPIO_TEST_MAX - fails, fails);
556 }
557