1 /*
2 * Copyright (c) 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 "light_driver.h"
10 #include <securec.h>
11 #include "device_resource_if.h"
12 #include "hdf_device_desc.h"
13 #include "osal_mem.h"
14 #include "osal_mutex.h"
15
16 #define HDF_LOG_TAG hdf_light_driver
17
18 #define LIGHT_WORK_QUEUE_NAME "light_queue"
19
20 struct LightDriverData *g_lightDrvData = NULL;
21
GetLightDrvData(void)22 static struct LightDriverData *GetLightDrvData(void)
23 {
24 return g_lightDrvData;
25 }
26
GetAllLightInfo(struct HdfSBuf * data,struct HdfSBuf * reply)27 static int32_t GetAllLightInfo(struct HdfSBuf *data, struct HdfSBuf *reply)
28 {
29 (void)data;
30 uint32_t i;
31 struct LightInfo lightInfo;
32 struct LightDriverData *drvData = NULL;
33
34 drvData = GetLightDrvData();
35 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
36 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM);
37
38 if (!HdfSbufWriteUint32(reply, drvData->lightNum)) {
39 HDF_LOGE("%s: write sbuf failed", __func__);
40 return HDF_FAILURE;
41 }
42
43 for (i = 0; i < LIGHT_ID_BUTT; ++i) {
44 if (drvData->info[i] == NULL) {
45 continue;
46 }
47 lightInfo.lightId = i;
48 lightInfo.reserved = 0;
49
50 if (!HdfSbufWriteBuffer(reply, &lightInfo, sizeof(lightInfo))) {
51 HDF_LOGE("%s: write sbuf failed", __func__);
52 return HDF_FAILURE;
53 }
54 }
55
56 return HDF_SUCCESS;
57 }
58
StartLight(uint32_t lightId)59 int32_t StartLight(uint32_t lightId)
60 {
61 struct LightDriverData *drvData = NULL;
62
63 drvData = GetLightDrvData();
64 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
65
66 if (GpioWrite(drvData->info[lightId]->busNum, GPIO_VAL_HIGH) != HDF_SUCCESS) {
67 HDF_LOGE("%s: pull gpio%d to %d level failed", __func__, drvData->info[lightId]->busNum, GPIO_VAL_LOW);
68 return HDF_FAILURE;
69 }
70
71 return HDF_SUCCESS;
72 }
73
StopLight(uint32_t lightId)74 int32_t StopLight(uint32_t lightId)
75 {
76 struct LightDriverData *drvData = NULL;
77
78 drvData = GetLightDrvData();
79 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
80
81 if (GpioWrite(drvData->info[lightId]->busNum, GPIO_VAL_LOW) != HDF_SUCCESS) {
82 HDF_LOGE("%s: pull gpio%d to %d level failed", __func__, drvData->info[lightId]->busNum, GPIO_VAL_LOW);
83 return HDF_FAILURE;
84 }
85
86 return HDF_SUCCESS;
87 }
88
LightTimerEntry(uintptr_t para)89 void LightTimerEntry(uintptr_t para)
90 {
91 uint32_t duration;
92 uint32_t lightId;
93 struct LightDriverData *drvData = NULL;
94
95 drvData = GetLightDrvData();
96 if (drvData == NULL) {
97 HDF_LOGE("%s: drvData is null", __func__);
98 return;
99 }
100
101 lightId = (uint32_t)para;
102 drvData->lightId = lightId;
103
104 if (drvData->info[lightId]->lightState == LIGHT_STATE_START) {
105 duration = drvData->info[lightId]->offTime;
106 }
107 if (drvData->info[lightId]->lightState == LIGHT_STATE_STOP) {
108 duration = drvData->info[lightId]->onTime;
109 }
110
111 HdfAddWork(&drvData->workQueue, &drvData->work);
112
113 if ((OsalTimerSetTimeout(&drvData->timer, duration) == HDF_SUCCESS)) {
114 return;
115 }
116
117 if (drvData->timer.realTimer != NULL) {
118 if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) {
119 HDF_LOGE("%s: delete light timer fail!", __func__);
120 }
121 }
122
123 return;
124 }
125
Enable(uint32_t lightId,struct HdfSBuf * data,struct HdfSBuf * reply)126 static int32_t Enable(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply)
127 {
128 (void)reply;
129 uint32_t len;
130 struct LightEffect *buf = NULL;
131 struct LightDriverData *drvData = NULL;
132
133 drvData = GetLightDrvData();
134 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
135
136 if (drvData->info[lightId] == NULL) {
137 HDF_LOGE("%s: light id info is null", __func__);
138 return HDF_FAILURE;
139 }
140
141 if (!HdfSbufReadBuffer(data, (const void **)&buf, &len)) {
142 HDF_LOGE("%s: light read data failed", __func__);
143 return HDF_FAILURE;
144 }
145
146 drvData->info[lightId]->lightBrightness = (buf->lightBrightness == 0) ?
147 drvData->info[lightId]->lightBrightness : buf->lightBrightness;
148
149 if ((drvData->info[lightId]->lightBrightness & LIGHT_MAKE_R_BIT) != 0) {
150 drvData->info[lightId]->busNum = drvData->info[lightId]->busRNum;
151 } else if ((drvData->info[lightId]->lightBrightness & LIGHT_MAKE_G_BIT) != 0) {
152 drvData->info[lightId]->busNum = drvData->info[lightId]->busGNum;
153 } else if ((drvData->info[lightId]->lightBrightness & LIGHT_MAKE_B_BIT) != 0) {
154 drvData->info[lightId]->busNum = drvData->info[lightId]->busBNum;
155 }
156
157 if (buf->flashEffect.flashMode == LIGHT_FLASH_NONE) {
158 if (GpioWrite(drvData->info[lightId]->busNum, GPIO_VAL_HIGH) != HDF_SUCCESS) {
159 HDF_LOGE("%s: gpio busNum %d write failed", __func__, drvData->info[lightId]->busNum);
160 return HDF_FAILURE;
161 }
162 }
163
164 if (buf->flashEffect.flashMode == LIGHT_FLASH_TIMED) {
165 drvData->info[lightId]->onTime = (buf->flashEffect.onTime < drvData->info[lightId]->onTime) ?
166 drvData->info[lightId]->onTime : buf->flashEffect.onTime;
167 drvData->info[lightId]->offTime = (buf->flashEffect.offTime < drvData->info[lightId]->offTime) ?
168 drvData->info[lightId]->offTime : buf->flashEffect.offTime;
169
170 if (OsalTimerCreate(&drvData->timer, LIGHT_WAIT_TIME, LightTimerEntry, (uintptr_t)lightId) != HDF_SUCCESS) {
171 HDF_LOGE("%s: create light timer fail!", __func__);
172 return HDF_FAILURE;
173 }
174
175 if (OsalTimerStartLoop(&drvData->timer) != HDF_SUCCESS) {
176 HDF_LOGE("%s: start light timer fail!", __func__);
177 return HDF_FAILURE;
178 }
179 }
180
181 return HDF_SUCCESS;
182 }
183
Disable(uint32_t lightId,struct HdfSBuf * data,struct HdfSBuf * reply)184 static int32_t Disable(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply)
185 {
186 (void)data;
187 (void)reply;
188 struct LightDriverData *drvData = NULL;
189
190 drvData = GetLightDrvData();
191 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
192
193 if (drvData->info[lightId] == NULL) {
194 HDF_LOGE("%s: light id info is null", __func__);
195 return HDF_FAILURE;
196 }
197
198 if (drvData->timer.realTimer != NULL) {
199 if (OsalTimerDelete(&drvData->timer) != HDF_SUCCESS) {
200 HDF_LOGE("%s: delete light timer fail!", __func__);
201 return HDF_FAILURE;
202 }
203 }
204
205 if (GpioWrite(drvData->info[lightId]->busRNum, GPIO_VAL_LOW) != HDF_SUCCESS) {
206 HDF_LOGE("%s: gpio write failed", __func__);
207 return HDF_FAILURE;
208 }
209
210 drvData->info[lightId]->lightState = LIGHT_STATE_STOP;
211
212 return HDF_SUCCESS;
213 }
214
215 static struct LightCmdHandleList g_lightCmdHandle[] = {
216 {LIGHT_OPS_IO_CMD_ENABLE, Enable},
217 {LIGHT_OPS_IO_CMD_DISABLE, Disable},
218 };
219
DispatchCmdHandle(uint32_t lightId,struct HdfSBuf * data,struct HdfSBuf * reply)220 static int32_t DispatchCmdHandle(uint32_t lightId, struct HdfSBuf *data, struct HdfSBuf *reply)
221 {
222 int32_t opsCmd;
223 int32_t loop;
224 int32_t count;
225
226 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
227
228 if (!HdfSbufReadInt32(data, &opsCmd)) {
229 HDF_LOGE("%s: sbuf read opsCmd failed", __func__);
230 return HDF_FAILURE;
231 }
232
233 if ((opsCmd >= LIGHT_OPS_IO_CMD_END) || (opsCmd < LIGHT_OPS_IO_CMD_ENABLE)) {
234 HDF_LOGE("%s: invalid cmd = %d", __func__, opsCmd);
235 return HDF_FAILURE;
236 }
237
238 count = sizeof(g_lightCmdHandle) / sizeof(g_lightCmdHandle[0]);
239 for (loop = 0; loop < count; ++loop) {
240 if ((opsCmd == g_lightCmdHandle[loop].cmd) && (g_lightCmdHandle[loop].func != NULL)) {
241 return g_lightCmdHandle[loop].func(lightId, data, reply);
242 }
243 }
244
245 return HDF_FAILURE;
246 }
247
DispatchLight(struct HdfDeviceIoClient * client,int32_t cmd,struct HdfSBuf * data,struct HdfSBuf * reply)248 static int32_t DispatchLight(struct HdfDeviceIoClient *client,
249 int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
250 {
251 int32_t ret;
252 uint32_t lightId;
253 struct LightDriverData *drvData = NULL;
254
255 drvData = GetLightDrvData();
256 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
257 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(client, HDF_ERR_INVALID_PARAM);
258
259 if (cmd >= LIGHT_IO_CMD_END) {
260 HDF_LOGE("%s: light cmd invalid para", __func__);
261 return HDF_ERR_INVALID_PARAM;
262 }
263
264 if (cmd == LIGHT_IO_CMD_GET_INFO_LIST) {
265 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(reply, HDF_ERR_INVALID_PARAM);
266 return GetAllLightInfo(data, reply);
267 }
268
269 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
270 (void)OsalMutexLock(&drvData->mutex);
271 if (!HdfSbufReadUint32(data, &lightId)) {
272 HDF_LOGE("%s: sbuf read lightId failed", __func__);
273 (void)OsalMutexUnlock(&drvData->mutex);
274 return HDF_ERR_INVALID_PARAM;
275 }
276
277 if (lightId >= LIGHT_ID_BUTT) {
278 HDF_LOGE("%s: light id invalid para", __func__);
279 (void)OsalMutexUnlock(&drvData->mutex);
280 return HDF_FAILURE;
281 }
282
283 ret = DispatchCmdHandle(lightId, data, reply);
284 (void)OsalMutexUnlock(&drvData->mutex);
285
286 return ret;
287 }
288
ParseLightInfo(const struct DeviceResourceNode * node,const struct DeviceResourceIface * parser)289 static int32_t ParseLightInfo(const struct DeviceResourceNode *node, const struct DeviceResourceIface *parser)
290 {
291 int32_t ret;
292 uint32_t i;
293 uint32_t temp;
294 uint32_t *lightBrightness = NULL;
295 struct LightDriverData *drvData = NULL;
296
297 drvData = GetLightDrvData();
298 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
299 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM);
300 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM);
301
302 drvData->lightNum = (uint32_t)parser->GetElemNum(node, "lightId");
303 if (drvData->lightNum > LIGHT_ID_NUM) {
304 HDF_LOGE("%s: lightNum cross the border", __func__);
305 return HDF_FAILURE;
306 }
307
308 ret = memset_s(drvData->info, sizeof(drvData->info[LIGHT_ID_NONE]) * LIGHT_ID_BUTT, 0,
309 sizeof(drvData->info[LIGHT_ID_NONE]) * LIGHT_ID_BUTT);
310 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "memset_s");
311
312 for (i = 0; i < drvData->lightNum; ++i) {
313 ret = parser->GetUint32ArrayElem(node, "lightId", i, &temp, 0);
314 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightId");
315
316 if (temp >= LIGHT_ID_BUTT) {
317 HDF_LOGE("%s: light id invalid para", __func__);
318 return HDF_FAILURE;
319 }
320
321 drvData->info[temp] = (struct LightDeviceInfo *)OsalMemCalloc(sizeof(struct LightDeviceInfo));
322 if (drvData->info[temp] == NULL) {
323 HDF_LOGE("%s: malloc fail", __func__);
324 return HDF_FAILURE;
325 }
326
327 ret = parser->GetUint32(node, "busRNum", &drvData->info[temp]->busRNum, 0);
328 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busRNum");
329 ret = parser->GetUint32(node, "busGNum", &drvData->info[temp]->busGNum, 0);
330 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busGNum");
331 ret = parser->GetUint32(node, "busBNum", &drvData->info[temp]->busBNum, 0);
332 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busBNum");
333 lightBrightness = (uint32_t *)&drvData->info[temp]->lightBrightness;
334 ret = parser->GetUint32(node, "lightBrightness", lightBrightness, 0);
335 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "lightBrightness");
336 ret = parser->GetUint32(node, "onTime", &drvData->info[temp]->onTime, 0);
337 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "onTime");
338 ret = parser->GetUint32(node, "offTime", &drvData->info[temp]->offTime, 0);
339 CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "offTime");
340
341 drvData->info[temp]->lightState = LIGHT_STATE_STOP;
342 }
343
344 return HDF_SUCCESS;
345 }
346
GetLightConfigData(const struct DeviceResourceNode * node)347 static int32_t GetLightConfigData(const struct DeviceResourceNode *node)
348 {
349 struct DeviceResourceIface *parser = NULL;
350 const struct DeviceResourceNode *light = NULL;
351 const struct DeviceResourceNode *childNode = NULL;
352
353 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM);
354
355 parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
356 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM);
357 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser->GetChildNode, HDF_ERR_INVALID_PARAM);
358
359 childNode = parser->GetChildNode(node, "lightAttr");
360 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(childNode, HDF_ERR_INVALID_PARAM);
361 light = parser->GetChildNode(childNode, "light01");
362 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(light, HDF_ERR_INVALID_PARAM);
363
364 if (ParseLightInfo(light, parser) != HDF_SUCCESS) {
365 HDF_LOGE("%s: ParseLightInfo is failed!", __func__);
366 return HDF_FAILURE;
367 }
368
369 return HDF_SUCCESS;
370 }
371
BindLightDriver(struct HdfDeviceObject * device)372 int32_t BindLightDriver(struct HdfDeviceObject *device)
373 {
374 struct LightDriverData *drvData = NULL;
375
376 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
377
378 drvData = (struct LightDriverData *)OsalMemCalloc(sizeof(*drvData));
379 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL);
380
381 drvData->ioService.Dispatch = DispatchLight;
382 drvData->device = device;
383 device->service = &drvData->ioService;
384 g_lightDrvData = drvData;
385
386 return HDF_SUCCESS;
387 }
388
LightWorkEntry(void * para)389 static void LightWorkEntry(void *para)
390 {
391 uint32_t lightId;
392 struct LightDriverData *drvData = (struct LightDriverData *)para;
393 CHECK_LIGHT_NULL_PTR_RETURN(drvData);
394 lightId = drvData->lightId;
395
396 if (drvData->info[lightId] == NULL) {
397 HDF_LOGE("%s: lightId info is NULL!", __func__);
398 return;
399 }
400
401 if (drvData->info[lightId]->lightState == LIGHT_STATE_START) {
402 if (StopLight(lightId) != HDF_SUCCESS) {
403 HDF_LOGE("%s: add light work fail! device state[%d]!", __func__, drvData->info[lightId]->lightState);
404 }
405 drvData->info[lightId]->lightState = LIGHT_STATE_STOP;
406 return;
407 }
408
409 if (drvData->info[lightId]->lightState == LIGHT_STATE_STOP) {
410 if (StartLight(lightId) != HDF_SUCCESS) {
411 HDF_LOGE("%s: add light work fail! device state[%d]!", __func__, drvData->info[lightId]->lightState);
412 }
413 drvData->info[lightId]->lightState = LIGHT_STATE_START;
414 return;
415 }
416 }
417
InitLightDriver(struct HdfDeviceObject * device)418 int32_t InitLightDriver(struct HdfDeviceObject *device)
419 {
420 struct LightDriverData *drvData = NULL;
421
422 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
423 drvData = (struct LightDriverData *)device->service;
424 CHECK_LIGHT_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE);
425
426 if (OsalMutexInit(&drvData->mutex) != HDF_SUCCESS) {
427 HDF_LOGE("%s: init mutex fail!", __func__);
428 return HDF_FAILURE;
429 }
430
431 if (HdfWorkQueueInit(&drvData->workQueue, LIGHT_WORK_QUEUE_NAME) != HDF_SUCCESS) {
432 HDF_LOGE("%s: init workQueue fail!", __func__);
433 return HDF_FAILURE;
434 }
435
436 if (HdfWorkInit(&drvData->work, LightWorkEntry, (void*)drvData) != HDF_SUCCESS) {
437 HDF_LOGE("%s: init work fail!", __func__);
438 return HDF_FAILURE;
439 }
440
441 if (GetLightConfigData(device->property) != HDF_SUCCESS) {
442 HDF_LOGE("%s: get light config fail!", __func__);
443 return HDF_FAILURE;
444 }
445
446 return HDF_SUCCESS;
447 }
448
ReleaseLightDriver(struct HdfDeviceObject * device)449 void ReleaseLightDriver(struct HdfDeviceObject *device)
450 {
451 int32_t i;
452 struct LightDriverData *drvData = NULL;
453
454 if (device == NULL) {
455 HDF_LOGE("%s: device is null", __func__);
456 return;
457 }
458
459 drvData = (struct LightDriverData *)device->service;
460 if (drvData == NULL) {
461 HDF_LOGE("%s: drvData is null", __func__);
462 return;
463 }
464
465 for (i = LIGHT_ID_NONE; i < LIGHT_ID_BUTT; ++i) {
466 if (drvData->info[i] != NULL) {
467 OsalMemFree(drvData->info[i]);
468 drvData->info[i] = NULL;
469 }
470 }
471
472 HdfWorkDestroy(&drvData->work);
473 HdfWorkQueueDestroy(&drvData->workQueue);
474 (void)OsalMutexDestroy(&drvData->mutex);
475 OsalMemFree(drvData);
476 g_lightDrvData = NULL;
477 }
478
479 struct HdfDriverEntry g_lightDriverEntry = {
480 .moduleVersion = 1,
481 .moduleName = "HDF_LIGHT",
482 .Bind = BindLightDriver,
483 .Init = InitLightDriver,
484 .Release = ReleaseLightDriver,
485 };
486
487 HDF_INIT(g_lightDriverEntry);
488