diff --git a/model/misc/vibrator/driver/chipset/vibrator_linear_driver.c b/model/misc/vibrator/driver/chipset/vibrator_linear_driver.c new file mode 100644 index 0000000000000000000000000000000000000000..014eb3c77a72d540b46baaec244f7f74ca9b80f3 --- /dev/null +++ b/model/misc/vibrator/driver/chipset/vibrator_linear_driver.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "device_resource_if.h" +#include "gpio_if.h" +#include "hdf_base.h" +#include "hdf_device_desc.h" +#include "osal_mem.h" +#include "securec.h" +#include "vibrator_driver.h" +#include "vibrator_driver_type.h" +#include "vibrator_linear_driver.h" + +#define HDF_LOG_TAG vibrator_linear_driver_c + +struct VibratorLinearDriverData *g_linearVibratorData = NULL; +static struct VibratorLinearDriverData *GetLinearVibratorData(void) +{ + return g_linearVibratorData; +} + +static int32_t StartLinearVibrator() +{ + struct VibratorLinearDriverData *drvData = GetLinearVibratorData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + if (drvData->busType != VIBRATOR_BUS_GPIO) { + HDF_LOGE("%s: vibrator bus type not gpio", __func__); + return HDF_FAILURE; + } + HDF_LOGE("%s: pull gpio high", __func__); + + return HDF_SUCCESS; +} + +static int32_t StartEffectLinearVibrator(uint32_t effectType) +{ + (void)effectType; + return HDF_SUCCESS; +} + +static int32_t StopLinearVibrator() +{ + struct VibratorLinearDriverData *drvData = GetLinearVibratorData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + if (drvData->busType != VIBRATOR_BUS_GPIO) { + HDF_LOGE("%s: vibrator bus type not gpio", __func__); + return HDF_FAILURE; + } + HDF_LOGE("%s: pull gpio low", __func__); + + return HDF_SUCCESS; +} + +static int32_t DispatchLinearVibrator(struct HdfDeviceIoClient *client, + int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + (void)client; + (void)cmd; + (void)data; + (void)reply; + + return HDF_SUCCESS; +} + +int32_t BindLinearVibratorDriver(struct HdfDeviceObject *device) +{ + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); + + struct VibratorLinearDriverData *drvData = (struct VibratorLinearDriverData *)OsalMemCalloc(sizeof(*drvData)); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL); + + drvData->ioService.Dispatch = DispatchLinearVibrator; + drvData->device = device; + device->service = &drvData->ioService; + g_linearVibratorData = drvData; + + return HDF_SUCCESS; +} + +static int32_t ParserLinearConfig(const struct DeviceResourceNode *node, struct VibratorLinearDriverData *drvData) +{ + int32_t ret; + struct DeviceResourceIface *parser = NULL; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(node, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(parser->GetChildNode, HDF_ERR_INVALID_PARAM); + + const struct DeviceResourceNode *configNode = parser->GetChildNode(node, "vibratorChipConfig"); + ret = parser->GetUint32(configNode, "busType", &drvData->busType, 0); + CHECK_VIBRATOR_PARSER_RESULT_RETURN_VALUE(ret, "busType"); + if (drvData->busType == VIBRATOR_BUS_GPIO) { + ret = parser->GetUint32(configNode, "gpioNum", &drvData->gpioNum, 0); + CHECK_VIBRATOR_PARSER_RESULT_RETURN_VALUE(ret, "gpioNum"); + } + + ret = parser->GetUint32(configNode, "startReg", &drvData->startReg, 0); + CHECK_VIBRATOR_PARSER_RESULT_RETURN_VALUE(ret, "startReg"); + ret = parser->GetUint32(configNode, "stopReg", &drvData->stopReg, 0); + CHECK_VIBRATOR_PARSER_RESULT_RETURN_VALUE(ret, "stopReg"); + ret = parser->GetUint32(configNode, "startMask", &drvData->mask, 0); + CHECK_VIBRATOR_PARSER_RESULT_RETURN_VALUE(ret, "startMask"); + + return HDF_SUCCESS; +} + +int32_t InitLinearVibratorDriver(struct HdfDeviceObject *device) +{ + static struct VibratorOps ops; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); + + struct VibratorLinearDriverData *drvData = (struct VibratorLinearDriverData *)device->service; + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + ops.Start = StartLinearVibrator; + ops.StartEffect = StartEffectLinearVibrator; + ops.Stop = StopLinearVibrator; + + if (RegisterVibrator(&ops) != HDF_SUCCESS) { + HDF_LOGE("%s: register vibrator ops fail", __func__); + return HDF_FAILURE; + } + + if (ParserLinearConfig(device->property, drvData) != HDF_SUCCESS) { + HDF_LOGE("%s: parser vibrator cfg fail", __func__); + return HDF_FAILURE; + } + + if (GpioSetDir(drvData->gpioNum, GPIO_DIR_OUT) != HDF_SUCCESS) { + HDF_LOGE("%s: set vibrator gpio fail", __func__); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +void ReleaseLinearVibratorDriver(struct HdfDeviceObject *device) +{ + struct VibratorLinearDriverData *drvData = (struct VibratorLinearDriverData *)device->service; + if (device == NULL || drvData == NULL) { + HDF_LOGE("%s: pointer is null and return errno", __func__); + return; + } + + (void)OsalMemFree(drvData); + g_linearVibratorData = NULL; +} + +struct HdfDriverEntry g_linearVibratorDriverEntry = { + .moduleVersion = 1, + .moduleName = "HDF_LINEAR_VIBRATOR", + .Bind = BindLinearVibratorDriver, + .Init = InitLinearVibratorDriver, + .Release = ReleaseLinearVibratorDriver, +}; + +HDF_INIT(g_linearVibratorDriverEntry); diff --git a/model/misc/vibrator/driver/chipset/vibrator_linear_driver.h b/model/misc/vibrator/driver/chipset/vibrator_linear_driver.h new file mode 100644 index 0000000000000000000000000000000000000000..6c194f1c2b231a34d2641caffb082e4add97da2a --- /dev/null +++ b/model/misc/vibrator/driver/chipset/vibrator_linear_driver.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef VIBRATOR_LINEAR_DRIVER_H +#define VIBRATOR_LINEAR_DRIVER_H + +#include "hdf_device_desc.h" + +struct VibratorLinearDriverData { + struct IDeviceIoService ioService; + struct HdfDeviceObject *device; + uint32_t busType; + uint32_t gpioNum; + uint32_t startReg; + uint32_t stopReg; + uint32_t mask; +}; + +#endif /* VIBRATOR_LINEAR_DRIVER_H */ diff --git a/model/misc/vibrator/driver/include/vibrator_driver.h b/model/misc/vibrator/driver/include/vibrator_driver.h new file mode 100644 index 0000000000000000000000000000000000000000..d6529669563ebfff843979ea88be6351a5d15f1d --- /dev/null +++ b/model/misc/vibrator/driver/include/vibrator_driver.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef VIBRATOR_DRIVER_H +#define VIBRATOR_DRIVER_H + +#include "osal_mutex.h" +#include "osal_timer.h" +#include "hdf_device_desc.h" +#include "hdf_workqueue.h" +#include "vibrator_driver_type.h" + +struct VibratorOps { + int32_t (*Start)(void); + int32_t (*StartEffect)(uint32_t effectType); + int32_t (*Stop)(void); +}; + +typedef int32_t (*VibratorCmdHandle)(struct HdfSBuf *reqData, struct HdfSBuf *reply); + +struct VibratorCmdHandleList { + int32_t cmd; + VibratorCmdHandle func; +}; + +struct VibratorDriverData { + struct IDeviceIoService ioService; + struct HdfDeviceObject *device; + HdfWorkQueue workQueue; + HdfWork work; + OsalTimer timer; + struct OsalMutex mutex; + enum VibratorConfigMode mode; + enum VibratorState state; + struct VibratorOps ops; +}; + +int32_t StartTimeVibrator(uint32_t time); +int32_t StopVibrator(void); +int32_t SetEffectVibrator(uint32_t type); +int32_t RegisterVibrator(struct VibratorOps *ops); + +#endif /* VIBRATOR_DRIVER_H */ diff --git a/model/misc/vibrator/driver/include/vibrator_driver_type.h b/model/misc/vibrator/driver/include/vibrator_driver_type.h new file mode 100644 index 0000000000000000000000000000000000000000..d4eeb96898b7ef209fa2f9f13624b14764b6b945 --- /dev/null +++ b/model/misc/vibrator/driver/include/vibrator_driver_type.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef VIBRATOR_DRIVER_TYPE_H +#define VIBRATOR_DRIVER_TYPE_H + +#include "hdf_log.h" + +#define CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(ptr, ret) do { \ + if ((ptr) == NULL) { \ + HDF_LOGE("%s:line %d pointer is null and return errno", __func__, __LINE__); \ + return (ret); \ + } \ +} while (0) + +#define CHECK_VIBRATOR_PARSER_RESULT_RETURN_VALUE(ret, str) do { \ + if (ret != HDF_SUCCESS) { \ + HDF_LOGE("%s:line %d %s fail, ret = %d!", __func__, __LINE__, str, ret); \ + return HDF_FAILURE; \ + } \ +} while (0) + +enum VibratorBusType { + VIBRATOR_BUS_I2C = 0, + VIBRATOR_BUS_GPIO = 1, +}; + +enum VibratorState { + VIBRATOR_STATE_IDLE = 0, + VIBRATOR_STATE_START_TIMER = 1, + VIBRATOR_STATE_STOP = 2, + VIBRATOR_STATE_SET_EFFECT = 3, +}; + +enum VibratorConfigMode { + VIBRATOR_MODE_ONCE = 0, // The mode of a one-shot vibration effect. + VIBRATOR_MODE_PRESET = 1, // The mode of a preset vibration effect. + VIBRATOR_MODE_BUTT = 0XFF, +}; + +enum VibratorDrvIoCmd { + VIBRATOR_DRV_IO_START_ONCE = 0, + VIBRATOR_DRV_IO_START_PRESET = 1, + VIBRATOR_DRV_IO_STOP = 2, + VIBRATOR_DRV_IO_END, +}; + +#endif /* VIBRATOR_DRIVER_TYPE_H */ diff --git a/model/misc/vibrator/driver/include/vibrator_haptic.h b/model/misc/vibrator/driver/include/vibrator_haptic.h new file mode 100644 index 0000000000000000000000000000000000000000..ef03c13827f2abb25833fa602e24fa66cdc147fb --- /dev/null +++ b/model/misc/vibrator/driver/include/vibrator_haptic.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef VIBRATOR_HAPTIC_H +#define VIBRATOR_HAPTIC_H + +#include "hdf_device_desc.h" +#include "hdf_dlist.h" +#include "osal_mutex.h" +#include "osal_sem.h" +#include "osal_thread.h" +#include "vibrator_driver_type.h" + +enum VibratorEffectType { + VIBRATOR_TYPE_EFFECT = 0, // Preset effect in device + VIBRATOR_TYPE_TIME = 1, // Preset effect by time +}; + +enum VibratorTimeSeqIndex { + VIBRATOR_TIME_DELAY_INDEX = 0, + VIBRATOR_TIME_DURATION_INDEX = 1, + VIBRATOR_TIME_INDEX_BUTT, +}; + +struct VibratorEffectNode { + const char *effect; + int32_t num; + uint32_t *seq; // The first element of seq is preset type referring to enum VibratorEffectType + struct DListHead node; +}; + +struct VibratorEffectCfg { + enum VibratorConfigMode cfgMode; // References enum VibratorConfigMode + uint32_t duration; + const char *effect; +}; + +struct VibratorHapticData { + bool supportPreset; + struct DListHead effectSeqHead; + struct OsalMutex mutex; + struct OsalSem hapticSem; + struct OsalThread hapticThread; + bool threadExitFlag; + uint32_t duration[VIBRATOR_TIME_INDEX_BUTT]; + int32_t effectType; + int32_t seqCount; + uint32_t *currentEffectSeq; +}; + +int32_t InitVibratorHaptic(struct HdfDeviceObject *device); +int32_t StartHaptic(struct VibratorEffectCfg *effectCfg); +int32_t StopHaptic(void); +int32_t DestroyHaptic(void); + +#endif /* VIBRATOR_HAPTIC_H */ diff --git a/model/misc/vibrator/driver/src/vibrator_driver.c b/model/misc/vibrator/driver/src/vibrator_driver.c new file mode 100644 index 0000000000000000000000000000000000000000..2b96f85a0425ab0ac718f725f831abd61804653c --- /dev/null +++ b/model/misc/vibrator/driver/src/vibrator_driver.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "securec.h" +#include "hdf_base.h" +#include "hdf_device_desc.h" +#include "osal_mem.h" +#include "vibrator_driver.h" +#include "vibrator_haptic.h" + +#define HDF_LOG_TAG vibrator_driver_c + +#define VIBRATOR_WORK_QUEUE_NAME "vibrator_queue" +#define VIBRATOR_START_TIME 10 + +struct VibratorDriverData *g_vibratorDrvData = NULL; + +static struct VibratorDriverData *GetVibratorDrvData(void) +{ + return g_vibratorDrvData; +} + +int32_t RegisterVibrator(struct VibratorOps *ops) +{ + struct VibratorDriverData *drvData = GetVibratorDrvData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(ops, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + (void)OsalMutexLock(&drvData->mutex); + drvData->ops.Start = ops->Start; + drvData->ops.StartEffect = ops->StartEffect; + drvData->ops.Stop = ops->Stop; + (void)OsalMutexUnlock(&drvData->mutex); + + return HDF_SUCCESS; +} + +void VibratorTimerEntry(uintptr_t para) +{ + struct VibratorDriverData *drvData = (struct VibratorDriverData *)para; + + drvData->state = VIBRATOR_STATE_STOP; + + HdfAddWork(&drvData->workQueue, &drvData->work); +} + +int32_t StartTimeVibrator(uint32_t time) +{ + int32_t ret; + struct VibratorDriverData *drvData = GetVibratorDrvData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData->ops.Start, HDF_FAILURE); + + (void)OsalMutexLock(&drvData->mutex); + drvData->state = VIBRATOR_STATE_START_TIMER; + + if (drvData->timer.realTimer != NULL) { + ret = OsalTimerDelete(&drvData->timer); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: delete vibrator timer fail!", __func__); + (void)OsalMutexUnlock(&drvData->mutex); + return HDF_FAILURE; + } + } + + if (OsalTimerCreate(&drvData->timer, time, VibratorTimerEntry, (uintptr_t)drvData) != HDF_SUCCESS) { + HDF_LOGE("%s: create vibrator Timer fail!", __func__); + (void)OsalMutexUnlock(&drvData->mutex); + return HDF_FAILURE; + } + + if (OsalTimerStartOnce(&drvData->timer) != HDF_SUCCESS) { + HDF_LOGE("%s: start vibrator time fail!", __func__); + (void)OsalMutexUnlock(&drvData->mutex); + return HDF_FAILURE; + } + + (void)OsalMutexUnlock(&drvData->mutex); + HdfAddWork(&drvData->workQueue, &drvData->work); + + return HDF_SUCCESS; +} + +int32_t StopVibrator() +{ + int32_t ret; + struct VibratorDriverData *drvData = GetVibratorDrvData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + (void)OsalMutexLock(&drvData->mutex); + drvData->state = VIBRATOR_STATE_STOP; + ret = OsalTimerDelete(&drvData->timer); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: delete vibrator timer fail!", __func__); + (void)OsalMutexUnlock(&drvData->mutex); + return HDF_FAILURE; + } + (void)OsalMutexUnlock(&drvData->mutex); + HdfAddWork(&drvData->workQueue, &drvData->work); + + return HDF_SUCCESS; +} + +int32_t SetEffectVibrator(uint32_t type) +{ + int32_t ret; + struct VibratorDriverData *drvData = GetVibratorDrvData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + (void)OsalMutexLock(&drvData->mutex); + if (drvData->ops.StartEffect != NULL) { + ret = drvData->ops.StartEffect(type); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: start effect fail", __func__); + (void)OsalMutexUnlock(&drvData->mutex); + return HDF_FAILURE; + } + } + drvData->state = VIBRATOR_STATE_SET_EFFECT; + (void)OsalMutexUnlock(&drvData->mutex); + + return HDF_SUCCESS; +} + +static void VibratorWorkEntry(void *para) +{ + int32_t ret = HDF_FAILURE; + struct VibratorDriverData *drvData = (struct VibratorDriverData *)para; + if (drvData == NULL) { + HDF_LOGE("%s: drvData is null", __func__); + return; + } + + if (drvData->state == VIBRATOR_STATE_START_TIMER) { + if (drvData->ops.Start != NULL) { + ret = drvData->ops.Start(); + } + } else if (drvData->state == VIBRATOR_STATE_STOP) { + if (drvData->ops.Stop != NULL) { + ret = drvData->ops.Stop(); + } + } + + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: set vibrator fail state[%d]!", __func__, drvData->state); + } +} + +static int32_t StartOnce(struct HdfSBuf *data, struct HdfSBuf *reply) +{ + uint32_t duration; + int32_t ret; + struct VibratorEffectCfg config; + struct VibratorDriverData *drvData = GetVibratorDrvData(); + (void)reply; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(data, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + if (drvData->mode == VIBRATOR_MODE_PRESET) { + if (StopHaptic() != HDF_SUCCESS) { + HDF_LOGE("%s: start haptic fail!", __func__); + return HDF_FAILURE; + } + } + + if (!HdfSbufReadUint32(data, &duration)) { + HDF_LOGE("%s: sbuf read duration failed", __func__); + return HDF_FAILURE; + } + + (void)OsalMutexLock(&drvData->mutex); + drvData->mode = VIBRATOR_MODE_ONCE; + (void)OsalMutexUnlock(&drvData->mutex); + + // start once time vibrate + config.cfgMode = VIBRATOR_MODE_ONCE; + config.duration = duration; + config.effect = NULL; + + ret = StartHaptic(&config); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: stop haptic fail!", __func__); + return ret; + } + + return HDF_SUCCESS; +} + +static int32_t StartEffect(struct HdfSBuf *data, struct HdfSBuf *reply) +{ + int32_t ret; + const char *effect = NULL; + struct VibratorEffectCfg config; + struct VibratorDriverData *drvData = GetVibratorDrvData(); + (void)reply; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(data, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + if (drvData->mode == VIBRATOR_MODE_ONCE) { + if (StopHaptic() != HDF_SUCCESS) { + HDF_LOGE("%s: stop haptic fail!", __func__); + return HDF_FAILURE; + } + } + + effect = HdfSbufReadString(data); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(effect, HDF_FAILURE); + + (void)OsalMutexLock(&drvData->mutex); + drvData->mode = VIBRATOR_MODE_PRESET; + (void)OsalMutexUnlock(&drvData->mutex); + + // start once time vibrate + config.cfgMode = VIBRATOR_MODE_PRESET; + config.duration = 0; + config.effect = effect; + + ret = StartHaptic(&config); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: start haptic fail!", __func__); + return ret; + } + + return HDF_SUCCESS; +} + +static int32_t Stop(struct HdfSBuf *data, struct HdfSBuf *reply) +{ + int32_t ret; + int32_t mode; + struct VibratorDriverData *drvData = GetVibratorDrvData(); + (void)reply; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(data, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + if (!HdfSbufReadInt32(data, &mode)) { + HDF_LOGE("%s: sbuf read mode failed", __func__); + return HDF_FAILURE; + } + + if ((mode != VIBRATOR_MODE_ONCE) && (mode != VIBRATOR_MODE_PRESET)) { + HDF_LOGE("%s: vibrator stop mode failed", __func__); + return HDF_FAILURE; + } + + ret = StopHaptic(); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: stop haptic fail!", __func__); + return ret; + } + + (void)OsalMutexLock(&drvData->mutex); + drvData->mode = VIBRATOR_MODE_BUTT; + (void)OsalMutexUnlock(&drvData->mutex); + + return HDF_SUCCESS; +} + +static struct VibratorCmdHandleList g_vibratorCmdHandle[] = { + {VIBRATOR_DRV_IO_START_ONCE, StartOnce}, + {VIBRATOR_DRV_IO_START_PRESET, StartEffect}, + {VIBRATOR_DRV_IO_STOP, Stop}, +}; + +static int32_t DispatchVibrator(struct HdfDeviceIoClient *client, + int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + int32_t loop; + + for (loop = 0; loop < sizeof(g_vibratorCmdHandle) / sizeof(g_vibratorCmdHandle[0]); ++loop) { + if ((cmd == g_vibratorCmdHandle[loop].cmd) && (g_vibratorCmdHandle[loop].func != NULL)) { + return g_vibratorCmdHandle[loop].func(data, reply); + } + } + + return HDF_SUCCESS; +} + +int32_t BindVibratorDriver(struct HdfDeviceObject *device) +{ + struct VibratorDriverData *drvData = NULL; + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); + + drvData = (struct VibratorDriverData *)OsalMemCalloc(sizeof(*drvData)); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL); + + drvData->ioService.Dispatch = DispatchVibrator; + drvData->device = device; + device->service = &drvData->ioService; + g_vibratorDrvData = drvData; + + return HDF_SUCCESS; +} + +int32_t InitVibratorDriver(struct HdfDeviceObject *device) +{ + struct VibratorDriverData *drvData = NULL; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); + drvData = (struct VibratorDriverData *)device->service; + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE); + + drvData->mode = VIBRATOR_MODE_BUTT; + drvData->state = VIBRATOR_STATE_IDLE; + + if (OsalMutexInit(&drvData->mutex) != HDF_SUCCESS) { + HDF_LOGE("%s: init mutex fail!", __func__); + return HDF_FAILURE; + } + + if (HdfWorkQueueInit(&drvData->workQueue, VIBRATOR_WORK_QUEUE_NAME) != HDF_SUCCESS) { + HDF_LOGE("%s: init workQueue fail!", __func__); + return HDF_FAILURE; + } + + if (HdfWorkInit(&drvData->work, VibratorWorkEntry, (void*)drvData) != HDF_SUCCESS) { + HDF_LOGE("%s: init workQueue fail!", __func__); + return HDF_FAILURE; + } + + if (InitVibratorHaptic(device) != HDF_SUCCESS) { + HDF_LOGE("%s: init workQueue fail!", __func__); + return HDF_FAILURE; + } + + return HDF_SUCCESS; +} + +void ReleaseVibratorDriver(struct HdfDeviceObject *device) +{ + struct VibratorDriverData *drvData = (struct VibratorDriverData *)device->service; + if (device == NULL || drvData == NULL) { + HDF_LOGE("%s: pointer is null and return errno", __func__); + return; + } + + StopHaptic(); + (void)DestroyHaptic(); + (void)OsalTimerDelete(&drvData->timer); + (void)OsalMutexDestroy(&drvData->mutex); + (void)OsalMemFree(drvData); + g_vibratorDrvData = NULL; +} + +struct HdfDriverEntry g_vibratorDriverEntry = { + .moduleVersion = 1, + .moduleName = "HDF_VIBRATOR", + .Bind = BindVibratorDriver, + .Init = InitVibratorDriver, + .Release = ReleaseVibratorDriver, +}; + +HDF_INIT(g_vibratorDriverEntry); diff --git a/model/misc/vibrator/driver/src/vibrator_haptic.c b/model/misc/vibrator/driver/src/vibrator_haptic.c new file mode 100644 index 0000000000000000000000000000000000000000..94279e9621c554e009e437a3dad9b50018677435 --- /dev/null +++ b/model/misc/vibrator/driver/src/vibrator_haptic.c @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "securec.h" +#include "device_resource_if.h" +#include "hdf_base.h" +#include "hdf_device_desc.h" +#include "osal_mem.h" +#include "vibrator_driver.h" +#include "vibrator_haptic.h" + +#define HDF_LOG_TAG vibrator_haptic_c +#define VIBRATOR_HAPTIC_STACK_SIZE 0x2000 +#define VIBRATOR_HAPTIC_SEQ_MAX 1024 +#define VIBRATOR_HAPTIC_SEQ_SIZE 4 +#define VIBRATOR_HAPTIC_SEQ_NAME_MAX 48 +#define VIBRATOR_HAPTIC_SEQ_SIZE_MAX (4 * VIBRATOR_HAPTIC_SEQ_MAX) + +struct VibratorHapticData *g_vibratorHapticData = NULL; + +static struct VibratorHapticData *GetHapticData(void) +{ + return g_vibratorHapticData; +} + +static struct VibratorEffectNode *MallocEffectNode(int32_t seqSize) +{ + uint32_t *seq = NULL; + struct VibratorEffectNode *node = NULL; + + if (seqSize <= 0 || seqSize > VIBRATOR_HAPTIC_SEQ_SIZE_MAX) { + HDF_LOGE("%s: malloc ", __func__); + return NULL; + } + + seq = (uint32_t *)OsalMemCalloc(seqSize); + if (seq == NULL) { + HDF_LOGE("%s: malloc seq fail", __func__); + return NULL; + } + + node = (struct VibratorEffectNode *)OsalMemCalloc(sizeof(*node)); + if (node == NULL) { + HDF_LOGE("%s: malloc seq fail", __func__); + OsalMemFree(seq); + return NULL; + } + node->seq = seq; + + return node; +} + +static int32_t ParserHapticEffect(struct DeviceResourceIface *parser, const struct DeviceResourceNode *hapticNode) +{ + int32_t ret; + int32_t count; + struct VibratorEffectNode *effectNode = NULL; + const struct DeviceResourceAttr *hapticAttr = NULL; + struct VibratorHapticData *hapticData = GetHapticData(); + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData, HDF_FAILURE); + + (void)OsalMutexLock(&hapticData->mutex); + DEV_RES_NODE_FOR_EACH_ATTR(hapticNode, hapticAttr) { + if ((hapticAttr == NULL) || (hapticAttr->name == NULL)) { + break; + } + + count = parser->GetElemNum(hapticNode, hapticAttr->name); + // Minimum of two elements, including the type and sequence. + if (count <= 1 || count > VIBRATOR_HAPTIC_SEQ_MAX) { + HDF_LOGD("%s: haptic [%s] parser seq count fail", __func__, hapticAttr->name); + continue; + } + + effectNode = MallocEffectNode(count * VIBRATOR_HAPTIC_SEQ_SIZE); + if (effectNode == NULL) { + HDF_LOGD("%s: malloc effect effectNode fail", __func__); + continue; + } + effectNode->effect = hapticAttr->name; + ret = parser->GetUint32Array(hapticNode, hapticAttr->name, effectNode->seq, count, 0); + CHECK_VIBRATOR_PARSER_RESULT_RETURN_VALUE(ret, hapticAttr->name); + effectNode->num = count; + DListInsertTail(&effectNode->node, &hapticData->effectSeqHead); + } + (void)OsalMutexUnlock(&hapticData->mutex); + + if (DListIsEmpty(&hapticData->effectSeqHead)) { + return HDF_FAILURE; + } + + return HDF_SUCCESS; +} + +static int32_t ParserVibratorHapticConfig(const struct DeviceResourceNode *node) +{ + bool supportPresetFlag = false; + struct DeviceResourceIface *parser = NULL; + const struct DeviceResourceNode *vibratorAttrNode = NULL; + const struct DeviceResourceNode *vibratorHapticNode = NULL; + struct VibratorHapticData *hapticData = GetHapticData(); + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM); + + parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(parser->GetChildNode, HDF_ERR_INVALID_PARAM); + + // get haptic type + vibratorAttrNode = parser->GetChildNode(node, "vibratorAttr"); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(vibratorAttrNode, HDF_ERR_INVALID_PARAM); + supportPresetFlag = parser->GetBool(vibratorAttrNode, "supportPreset"); + if (!supportPresetFlag) { + HDF_LOGD("%s: vibrator not support effect", __func__); + return HDF_SUCCESS; + } + + (void)OsalMutexLock(&hapticData->mutex); + hapticData->supportPreset = supportPresetFlag; + (void)OsalMutexUnlock(&hapticData->mutex); + + // malloc haptic resource + vibratorHapticNode = parser->GetChildNode(node, "vibratorHapticConfig"); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(vibratorHapticNode, HDF_ERR_INVALID_PARAM); + if (ParserHapticEffect(parser, vibratorHapticNode) != HDF_SUCCESS) { + HDF_LOGE("%s: vibrator get effect fail", __func__); + return HDF_FAILURE; + } + + return HDF_SUCCESS; +} + +static int32_t DelayTimeForEffect(struct OsalSem *sem, uint32_t time) +{ + int32_t ret; + if (time == 0) { + return HDF_SUCCESS; + } + + ret = OsalSemWait(sem, time); + if (ret == 0) { + HDF_LOGD("%s: haptic need break", __func__); + return -1; + } + + return HDF_SUCCESS; +} + +static int32_t HapticThreadEntry(void *para) +{ + int32_t count; + int32_t index = 0; + uint32_t delaytime; + uint32_t effect; + struct VibratorHapticData *hapticData = NULL; + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(para, HDF_FAILURE); + hapticData = (struct VibratorHapticData *)para; + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData->currentEffectSeq, HDF_FAILURE); + + count = hapticData->seqCount; + if (count <= 1 || count > VIBRATOR_HAPTIC_SEQ_MAX) { + HDF_LOGE("%s: count para invalid", __func__); + return HDF_ERR_INVALID_PARAM; + } + + while (!hapticData->threadExitFlag) { + if (index + 1 >= count) { + break; + } + + delaytime = hapticData->currentEffectSeq[index]; + if (DelayTimeForEffect(&hapticData->hapticSem, delaytime) < 0) { + continue; + } + + index++; + effect = hapticData->currentEffectSeq[index++]; + if (hapticData->effectType == VIBRATOR_TYPE_EFFECT) { + SetEffectVibrator(effect); + } else if (hapticData->effectType == VIBRATOR_TYPE_TIME) { + StartTimeVibrator(effect); + } + } + + (void)OsalMutexLock(&hapticData->mutex); + hapticData->threadExitFlag = true; + (void)OsalMutexUnlock(&hapticData->mutex); + + return HDF_SUCCESS; +} + +int32_t InitVibratorHaptic(struct HdfDeviceObject *device) +{ + struct VibratorHapticData *hapticData = NULL; + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE); + + hapticData = (struct VibratorHapticData *)OsalMemCalloc(sizeof(*hapticData)); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData, HDF_ERR_MALLOC_FAIL); + g_vibratorHapticData = hapticData; + hapticData->threadExitFlag = true; + hapticData->supportPreset = false; + + if (OsalMutexInit(&hapticData->mutex) != HDF_SUCCESS) { + HDF_LOGE("%s: fail to create thread lock", __func__); + goto EXIT; + } + + if (OsalSemInit(&hapticData->hapticSem, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: fail to create thread lock", __func__); + goto EXIT; + } + + // create thread + if (OsalThreadCreate(&hapticData->hapticThread, HapticThreadEntry, (void *)hapticData) != HDF_SUCCESS) { + HDF_LOGE("%s: create haptic thread fail!", __func__); + goto EXIT; + } + DListHeadInit(&hapticData->effectSeqHead); + + // get haptic hcs + if (ParserVibratorHapticConfig(device->property) != HDF_SUCCESS) { + hapticData->threadExitFlag = true; + HDF_LOGE("%s: parser haptic config fail!", __func__); + goto EXIT; + } + + return HDF_SUCCESS; +EXIT: + OsalMemFree(hapticData); + return HDF_FAILURE; +} + +static int32_t GetHapticSeqByEffect(struct VibratorEffectCfg *effectCfg) +{ + struct VibratorHapticData *hapticData = NULL; + struct VibratorEffectNode *pos = NULL; + struct VibratorEffectNode *tmp = NULL; + + hapticData = GetHapticData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData, HDF_FAILURE); + + if (effectCfg->cfgMode == VIBRATOR_MODE_ONCE) { + (void)OsalMutexLock(&hapticData->mutex); + hapticData->duration[VIBRATOR_TIME_DELAY_INDEX] = 0; + hapticData->duration[VIBRATOR_TIME_DURATION_INDEX] = effectCfg->duration; + hapticData->effectType = VIBRATOR_TYPE_TIME; + hapticData->seqCount = VIBRATOR_TIME_INDEX_BUTT; + hapticData->currentEffectSeq = &hapticData->duration[0]; + (void)OsalMutexUnlock(&hapticData->mutex); + } else if (effectCfg->cfgMode == VIBRATOR_MODE_PRESET) { + if (effectCfg->effect == NULL) { + HDF_LOGE("%s: effect para invalid!", __func__); + return HDF_FAILURE; + } + + hapticData->seqCount = 0; + hapticData->currentEffectSeq = NULL; + DLIST_FOR_EACH_ENTRY_SAFE(pos, tmp, &hapticData->effectSeqHead, struct VibratorEffectNode, node) { + if (strcmp(effectCfg->effect, pos->effect) == 0 && pos->seq != NULL) { + (void)OsalMutexLock(&hapticData->mutex); + hapticData->effectType = pos->seq[0]; + hapticData->seqCount = pos->num - 1; + hapticData->currentEffectSeq = &(pos->seq[1]); + (void)OsalMutexUnlock(&hapticData->mutex); + break; + } + } + if (hapticData->seqCount <= 0) { + HDF_LOGE("%s: not find effect type!", __func__); + return HDF_FAILURE; + } + } + + return HDF_SUCCESS; +} + +int32_t StartHaptic(struct VibratorEffectCfg *effectCfg) +{ + int32_t ret; + struct OsalThreadParam threadCfg; + struct VibratorHapticData *hapticData = GetHapticData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(effectCfg, HDF_FAILURE); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData, HDF_FAILURE); + + if (!hapticData->threadExitFlag) { + OsalSemPost(&hapticData->hapticSem); + return HDF_SUCCESS; + } + + ret = GetHapticSeqByEffect(effectCfg); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: get haptic seq fail!", __func__); + return ret; + } + + (void)OsalMutexLock(&hapticData->mutex); + hapticData->threadExitFlag = false; + (void)OsalMutexUnlock(&hapticData->mutex); + + threadCfg.name = "vibrator_haptic"; + threadCfg.priority = OSAL_THREAD_PRI_DEFAULT; + threadCfg.stackSize = VIBRATOR_HAPTIC_STACK_SIZE; + ret = OsalThreadStart(&hapticData->hapticThread, &threadCfg); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: start haptic thread fail!", __func__); + return ret; + } + + return HDF_SUCCESS; +} + +int32_t StopHaptic() +{ + struct VibratorHapticData *hapticData = GetHapticData(); + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData, HDF_FAILURE); + + if (hapticData->threadExitFlag) { + return HDF_SUCCESS; + } + + (void)OsalMutexLock(&hapticData->mutex); + hapticData->threadExitFlag = true; + (void)OsalMutexUnlock(&hapticData->mutex); + OsalSemPost(&hapticData->hapticSem); + StopVibrator(); + + return HDF_SUCCESS; +} + +static void ReleaseHapticConfig() +{ + struct VibratorHapticData *hapticData = GetHapticData(); + struct VibratorEffectNode *pos = NULL; + struct VibratorEffectNode *tmp = NULL; + + if (hapticData == NULL) { + return; + } + + (void)OsalMutexLock(&hapticData->mutex); + DLIST_FOR_EACH_ENTRY_SAFE(pos, tmp, &hapticData->effectSeqHead, struct VibratorEffectNode, node) { + if (pos->seq != NULL) { + OsalMemFree(pos->seq); + pos->seq = NULL; + } + pos->effect = NULL; + DListRemove(&pos->node); + OsalMemFree(pos); + } + (void)OsalMutexUnlock(&hapticData->mutex); +} + +int32_t DestroyHaptic() +{ + struct VibratorHapticData *hapticData = GetHapticData(); + + CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData, HDF_FAILURE); + if (hapticData->supportPreset) { + ReleaseHapticConfig(); + } + + (void)OsalMutexDestroy(&hapticData->mutex); + (void)OsalSemDestroy(&hapticData->hapticSem); + (void)OsalThreadDestroy(&hapticData->hapticThread); + + return HDF_SUCCESS; +}