/* * osal_timer.c * * osal driver * * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include "osal_timer.h" #include #include #include #include #include "hdf_log.h" #include "osal_mem.h" #include "osal_mutex.h" #define HDF_LOG_TAG osal_timer typedef enum { OSAL_TIMER_ONCE, OSAL_TIMER_LOOP, } OsalTimerMode; struct osal_ktimer { unsigned long arg; struct timer_list timer; OsalTimerFunc func; uint32_t msec; struct OsalMutex mutex; OsalTimerMode mode; bool stop_flag; }; static void osal_timer_callback(struct timer_list *arg) { struct osal_ktimer *ktimer = NULL; uint32_t msec; OsalTimerMode mode; bool stop_flag = false; if (arg == NULL) { HDF_LOGI("%s timer is stopped", __func__); return; } ktimer = from_timer(ktimer, arg, timer); OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER); mode = ktimer->mode; stop_flag = ktimer->stop_flag; OsalMutexUnlock(&ktimer->mutex); if (!stop_flag) { ktimer->func(ktimer->arg); OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER); msec = ktimer->msec; OsalMutexUnlock(&ktimer->mutex); if (mode == OSAL_TIMER_LOOP) { ktimer->timer.expires = jiffies + msecs_to_jiffies(msec); mod_timer(&ktimer->timer, ktimer->timer.expires); } } else { del_timer(&ktimer->timer); OsalMutexDestroy(&ktimer->mutex); OsalMemFree(ktimer); HDF_LOGI("%s timer is stop", __func__); } } int32_t OsalTimerCreate(OsalTimer *timer, uint32_t interval, OsalTimerFunc func, uintptr_t arg) { struct osal_ktimer *ktimer = NULL; if (func == NULL || timer == NULL || interval == 0) { HDF_LOGE("%s invalid para", __func__); return HDF_ERR_INVALID_PARAM; } ktimer = (struct osal_ktimer *)OsalMemCalloc(sizeof(*ktimer)); if (ktimer == NULL) { HDF_LOGE("%s malloc fail", __func__); timer->realTimer = NULL; return HDF_ERR_MALLOC_FAIL; } ktimer->arg = arg; ktimer->func = func; ktimer->msec = interval; ktimer->stop_flag = false; OsalMutexInit(&ktimer->mutex); timer->realTimer = (void *)ktimer; return HDF_SUCCESS; } EXPORT_SYMBOL(OsalTimerCreate); static int32_t OsalTimerStart(OsalTimer *timer, OsalTimerMode mode) { struct osal_ktimer *ktimer = NULL; struct timer_list *timer_id = NULL; if (timer == NULL || timer->realTimer == NULL) { HDF_LOGE("%s invalid para", __func__); return HDF_ERR_INVALID_PARAM; } ktimer = (struct osal_ktimer *)timer->realTimer; timer_id = &ktimer->timer; timer_setup(timer_id, osal_timer_callback, 0); ktimer->mode = mode; timer_id->expires = jiffies + msecs_to_jiffies(ktimer->msec); add_timer(timer_id); return HDF_SUCCESS; } int32_t OsalTimerStartOnce(OsalTimer *timer) { return OsalTimerStart(timer, OSAL_TIMER_ONCE); } EXPORT_SYMBOL(OsalTimerStartOnce); int32_t OsalTimerStartLoop(OsalTimer *timer) { return OsalTimerStart(timer, OSAL_TIMER_LOOP); } EXPORT_SYMBOL(OsalTimerStartLoop); int32_t OsalTimerSetTimeout(OsalTimer *timer, uint32_t interval) { struct osal_ktimer *ktimer = NULL; if (timer == NULL || timer->realTimer == NULL || interval == 0) { HDF_LOGE("%s invalid para", __func__); return HDF_ERR_INVALID_PARAM; } ktimer = (struct osal_ktimer *)timer->realTimer; if (ktimer->msec == interval) return HDF_SUCCESS; OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER); ktimer->msec = interval; OsalMutexUnlock(&ktimer->mutex); return HDF_SUCCESS; } EXPORT_SYMBOL(OsalTimerSetTimeout); int32_t OsalTimerDelete(OsalTimer *timer) { struct osal_ktimer *ktimer = NULL; if (timer == NULL || timer->realTimer == NULL) { HDF_LOGE("%s invalid para", __func__); return HDF_ERR_INVALID_PARAM; } ktimer = (struct osal_ktimer *)timer->realTimer; OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER); ktimer->stop_flag = true; OsalMutexUnlock(&ktimer->mutex); if (ktimer->mode == OSAL_TIMER_ONCE) mod_timer(&ktimer->timer, ktimer->timer.expires); timer->realTimer = NULL; return HDF_SUCCESS; } EXPORT_SYMBOL(OsalTimerDelete);