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