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