1034 lines
28 KiB
C
1034 lines
28 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright(c) 2019 Realtek Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* 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.
|
|
*
|
|
*****************************************************************************/
|
|
#define _PHL_LED_C_
|
|
#include "phl_headers.h"
|
|
|
|
#define PHL_LED_INTERVALS_ARR_LEN_MAX 4
|
|
|
|
struct phl_led_event_args_t {
|
|
enum rtw_led_state state_condition;
|
|
struct rtw_led_action_args_t *action_args_arr;
|
|
u8 action_args_arr_len;
|
|
u32 toggle_delay_unit;
|
|
struct phl_led_event_args_t *next;
|
|
};
|
|
|
|
struct phl_led_timer_args_t {
|
|
struct phl_info_t *phl_info;
|
|
_os_timer timer;
|
|
u32 delay_unit;
|
|
bool timer_alive;
|
|
bool is_avail;
|
|
u32 led_manage_mask;
|
|
};
|
|
|
|
struct phl_led_info_t {
|
|
enum rtw_led_ctrl_mode ctrl_mode;
|
|
enum rtw_led_ctrl_mode reg_ctrl_mode;
|
|
enum rtw_led_opt curr_opt;
|
|
const struct rtw_led_toggle_args_t *toggle_args;
|
|
struct phl_led_timer_args_t *toggle_timer_args;
|
|
u32 toggle_interval_counter;
|
|
u32 toggle_start_delay_counter;
|
|
bool toggle_start_delay_over;
|
|
u32 toggle_loop_counter;
|
|
u8 toggle_curr_interval_idx;
|
|
};
|
|
|
|
struct phl_led_ctrl_t {
|
|
struct phl_led_info_t led_info_arr[RTW_LED_ID_LENGTH];
|
|
struct phl_led_event_args_t *event_args_list_arr[RTW_LED_EVENT_LENGTH];
|
|
struct rtw_led_intervals_t intervals_arr[PHL_LED_INTERVALS_ARR_LEN_MAX];
|
|
enum rtw_led_state state;
|
|
struct phl_led_timer_args_t *toggle_timer_args[RTW_LED_TIMER_LENGTH];
|
|
};
|
|
|
|
static void _phl_led_timer_release(struct phl_led_timer_args_t *timer_args)
|
|
{
|
|
void *drv_priv = phl_to_drvpriv(timer_args->phl_info);
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_manage_mask == 0x%x\n",
|
|
__func__, timer_args->led_manage_mask);
|
|
|
|
_os_cancel_timer(drv_priv, &(timer_args->timer));
|
|
_os_release_timer(drv_priv, &(timer_args->timer));
|
|
_os_mem_free(drv_priv, timer_args, sizeof(struct phl_led_timer_args_t));
|
|
}
|
|
|
|
static void _phl_led_remove_from_timer(struct phl_led_info_t *led_info,
|
|
enum rtw_led_id led_id)
|
|
{
|
|
u32 *mask = NULL;
|
|
|
|
if (led_info->toggle_timer_args != NULL) {
|
|
mask = &(led_info->toggle_timer_args->led_manage_mask);
|
|
*mask &= ~(BIT(led_id));
|
|
|
|
if (*mask == 0)
|
|
led_info->toggle_timer_args->timer_alive = false;
|
|
|
|
led_info->toggle_timer_args = NULL;
|
|
led_info->toggle_args = NULL;
|
|
}
|
|
}
|
|
|
|
static void _phl_led_timer_cb_done(void* priv, struct phl_msg* msg)
|
|
{
|
|
struct phl_led_timer_args_t *timer_args =
|
|
(struct phl_led_timer_args_t *)(msg->inbuf);
|
|
|
|
if (!timer_args->timer_alive)
|
|
timer_args->is_avail = true;
|
|
}
|
|
|
|
static void _phl_led_timer_cb(void *args)
|
|
{
|
|
struct phl_led_timer_args_t *timer_args =
|
|
(struct phl_led_timer_args_t *) args;
|
|
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
|
|
struct phl_info_t *phl_info = timer_args->phl_info;
|
|
|
|
struct phl_msg msg = {0};
|
|
struct phl_msg_attribute attr = {0};
|
|
|
|
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_LED);
|
|
SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_LED_TICK);
|
|
msg.band_idx = HW_BAND_0;
|
|
msg.inbuf = (u8 *)(timer_args);
|
|
msg.inlen = sizeof(struct phl_led_timer_args_t);
|
|
|
|
attr.completion.completion = _phl_led_timer_cb_done;
|
|
attr.completion.priv = phl_info;
|
|
|
|
phl_status = phl_disp_eng_send_msg(timer_args->phl_info,
|
|
&msg, &attr, NULL);
|
|
if(phl_status != RTW_PHL_STATUS_SUCCESS){
|
|
PHL_ERR("%s: phl_disp_eng_send_msg failed!\n", __func__);
|
|
timer_args->timer_alive = false;
|
|
_phl_led_timer_cb_done(phl_info, &msg);
|
|
}
|
|
}
|
|
|
|
static enum rtw_phl_status _phl_led_ctrl_write_opt(void *hal,
|
|
enum rtw_led_id led_id,
|
|
enum rtw_led_opt *curr_opt,
|
|
enum rtw_led_opt opt)
|
|
{
|
|
if (opt >= RTW_LED_OPT_UNKNOWN) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: unknown opt (%d)\n",
|
|
__func__, opt);
|
|
return RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
|
|
if (RTW_HAL_STATUS_SUCCESS != rtw_hal_led_control(hal, led_id, opt))
|
|
return RTW_PHL_STATUS_FAILURE;
|
|
|
|
*curr_opt = opt;
|
|
return RTW_PHL_STATUS_SUCCESS;
|
|
}
|
|
|
|
static enum rtw_phl_status
|
|
_phl_led_ctrl_start_delay_hdlr(void *hal, struct phl_led_info_t *led_info,
|
|
enum rtw_led_id led_id)
|
|
{
|
|
if (led_info->toggle_start_delay_counter >=
|
|
led_info->toggle_args->start_delay) {
|
|
|
|
led_info->toggle_start_delay_over = true;
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: start delay is over\n",
|
|
__func__);
|
|
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_write_opt(hal, led_id, &(led_info->curr_opt),
|
|
led_info->toggle_args->start_opt))
|
|
return RTW_PHL_STATUS_FAILURE;
|
|
|
|
return RTW_PHL_STATUS_SUCCESS;
|
|
}
|
|
|
|
(led_info->toggle_start_delay_counter)++;
|
|
|
|
return RTW_PHL_STATUS_SUCCESS;
|
|
}
|
|
|
|
static enum rtw_phl_status
|
|
_phl_led_ctrl_interval_hdlr(void *hal, struct phl_led_info_t *led_info,
|
|
enum rtw_led_id led_id,
|
|
struct rtw_led_intervals_t *intervals)
|
|
{
|
|
u32 interval = 0;
|
|
enum rtw_led_opt opt = RTW_LED_OPT_UNKNOWN;
|
|
|
|
if (intervals == NULL) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: intervals == NULL\n",
|
|
__func__);
|
|
return RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
|
|
if (intervals->interval_arr == NULL) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: interval_arr == NULL\n", __func__);
|
|
return RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
|
|
if (led_info->toggle_curr_interval_idx >= intervals->len) {
|
|
PHL_TRACE(
|
|
COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: curr_interval_idx ( %d ) >= intervals' len ( %d )\n",
|
|
__func__, led_info->toggle_curr_interval_idx,
|
|
intervals->len);
|
|
return RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
|
|
interval = intervals->interval_arr[led_info->toggle_curr_interval_idx];
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: curr_interval_idx == %d, interval == %d, "
|
|
"interval_counter == %d\n",
|
|
__func__, led_info->toggle_curr_interval_idx, interval,
|
|
led_info->toggle_interval_counter);
|
|
|
|
if (interval > ++(led_info->toggle_interval_counter))
|
|
/* it is not time to toggle */
|
|
return RTW_PHL_STATUS_SUCCESS;
|
|
|
|
led_info->toggle_interval_counter = 0;
|
|
|
|
/* set curr_interval_idx to next */
|
|
if (++(led_info->toggle_curr_interval_idx) >= intervals->len) {
|
|
led_info->toggle_curr_interval_idx = 0;
|
|
if (led_info->toggle_args->loop > 0)
|
|
(led_info->toggle_loop_counter)++;
|
|
}
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: toggle led_id: %d\n", __func__,
|
|
led_id);
|
|
|
|
if (led_info->curr_opt == RTW_LED_OPT_LOW)
|
|
opt = RTW_LED_OPT_HIGH;
|
|
|
|
else if (led_info->curr_opt == RTW_LED_OPT_HIGH)
|
|
opt = RTW_LED_OPT_LOW;
|
|
|
|
else {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: incorrect curr_opt ( %d ). led_id: %d\n",
|
|
__func__, led_info->curr_opt, led_id);
|
|
return RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_write_opt(hal, led_id, &(led_info->curr_opt), opt))
|
|
return RTW_PHL_STATUS_FAILURE;
|
|
|
|
return RTW_PHL_STATUS_SUCCESS;
|
|
}
|
|
|
|
static enum rtw_phl_status
|
|
_phl_led_ctrl_toggle_hdlr(struct phl_led_timer_args_t *timer_args)
|
|
{
|
|
enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
|
|
void *drv_priv = phl_to_drvpriv(timer_args->phl_info);
|
|
|
|
enum rtw_led_id led_id = 0;
|
|
struct phl_led_ctrl_t *led_ctrl =
|
|
(struct phl_led_ctrl_t *)(timer_args->phl_info->led_ctrl);
|
|
struct phl_led_info_t *led_info = NULL;
|
|
|
|
u8 intervals_idx = 0;
|
|
|
|
for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
|
|
if ((timer_args->led_manage_mask & BIT(led_id)) == 0)
|
|
continue;
|
|
|
|
led_info = &(led_ctrl->led_info_arr[led_id]);
|
|
|
|
/* start_delay handling */
|
|
if (!led_info->toggle_start_delay_over) {
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_start_delay_hdlr(
|
|
timer_args->phl_info->hal, led_info, led_id)) {
|
|
|
|
status = RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* start_delay is over, handle intervals */
|
|
intervals_idx = led_info->toggle_args->intervals_idx;
|
|
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_interval_hdlr(
|
|
timer_args->phl_info->hal, led_info, led_id,
|
|
&(led_ctrl->intervals_arr[intervals_idx]))) {
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: intervals handling failed. led_id: %d\n",
|
|
__func__, led_id);
|
|
status = RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
|
|
if (led_info->toggle_args->loop > 0 &&
|
|
led_info->toggle_args->loop ==
|
|
led_info->toggle_loop_counter) {
|
|
|
|
_phl_led_remove_from_timer(led_info, led_id);
|
|
}
|
|
}
|
|
|
|
if (timer_args->timer_alive)
|
|
_os_set_timer(drv_priv, &(timer_args->timer),
|
|
timer_args->delay_unit);
|
|
|
|
return status;
|
|
}
|
|
|
|
static enum rtw_phl_status
|
|
_phl_led_ctrl_action_hdlr(struct phl_info_t *phl_info, enum rtw_led_id led_id,
|
|
enum rtw_led_action action,
|
|
struct rtw_led_toggle_args_t *toggle_args,
|
|
struct phl_led_timer_args_t **timer_args_ptr)
|
|
{
|
|
enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
|
|
|
|
struct phl_led_ctrl_t *led_ctrl =
|
|
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
|
|
struct phl_led_info_t *led_info = &(led_ctrl->led_info_arr[led_id]);
|
|
enum rtw_led_ctrl_mode target_ctrl_mode;
|
|
u8 i = 0;
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: led_id == %d, action == 0X%X\n", __func__, led_id,
|
|
action);
|
|
|
|
/* Set ctrl mode*/
|
|
switch (action) {
|
|
case RTW_LED_ACTION_LOW:
|
|
case RTW_LED_ACTION_HIGH:
|
|
case RTW_LED_ACTION_TOGGLE:
|
|
target_ctrl_mode = led_info->reg_ctrl_mode;
|
|
break;
|
|
case RTW_LED_ACTION_HW_TRX:
|
|
target_ctrl_mode = RTW_LED_CTRL_HW_TRX_MODE;
|
|
break;
|
|
default:
|
|
target_ctrl_mode = led_info->ctrl_mode;
|
|
break;
|
|
}
|
|
if(led_info->ctrl_mode != target_ctrl_mode){
|
|
if (rtw_hal_led_set_ctrl_mode(phl_info->hal, led_id,
|
|
target_ctrl_mode)){
|
|
status = RTW_PHL_STATUS_FAILURE;
|
|
return status;
|
|
}
|
|
led_info->ctrl_mode = target_ctrl_mode;
|
|
}
|
|
|
|
/* Sw action */
|
|
switch (action) {
|
|
case RTW_LED_ACTION_LOW:
|
|
if(led_info->ctrl_mode != RTW_LED_CTRL_SW_PP_MODE &&
|
|
led_info->ctrl_mode != RTW_LED_CTRL_SW_OD_MODE)
|
|
break;
|
|
|
|
_phl_led_remove_from_timer(led_info, led_id);
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_write_opt(phl_info->hal, led_id,
|
|
&(led_info->curr_opt),
|
|
RTW_LED_OPT_LOW))
|
|
status = RTW_PHL_STATUS_FAILURE;
|
|
|
|
break;
|
|
|
|
case RTW_LED_ACTION_HIGH:
|
|
if(led_info->ctrl_mode != RTW_LED_CTRL_SW_PP_MODE &&
|
|
led_info->ctrl_mode != RTW_LED_CTRL_SW_OD_MODE)
|
|
break;
|
|
|
|
_phl_led_remove_from_timer(led_info, led_id);
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_write_opt(phl_info->hal, led_id,
|
|
&(led_info->curr_opt),
|
|
RTW_LED_OPT_HIGH))
|
|
status = RTW_PHL_STATUS_FAILURE;
|
|
|
|
break;
|
|
|
|
case RTW_LED_ACTION_HW_TRX:
|
|
_phl_led_remove_from_timer(led_info, led_id);
|
|
break;
|
|
|
|
case RTW_LED_ACTION_TOGGLE:
|
|
if(led_info->ctrl_mode != RTW_LED_CTRL_SW_PP_MODE &&
|
|
led_info->ctrl_mode != RTW_LED_CTRL_SW_OD_MODE)
|
|
break;
|
|
|
|
_phl_led_remove_from_timer(led_info, led_id);
|
|
|
|
led_info->toggle_args = toggle_args;
|
|
|
|
led_info->toggle_interval_counter = 0;
|
|
led_info->toggle_start_delay_counter = toggle_args->start_delay;
|
|
led_info->toggle_start_delay_over = false;
|
|
led_info->toggle_loop_counter = 0;
|
|
led_info->toggle_curr_interval_idx = 0;
|
|
|
|
if (*timer_args_ptr == NULL) {
|
|
for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
|
|
if (led_ctrl->toggle_timer_args[i] == NULL)
|
|
continue;
|
|
if (led_ctrl->toggle_timer_args[i]->is_avail ==
|
|
true) {
|
|
*timer_args_ptr =
|
|
led_ctrl->toggle_timer_args[i];
|
|
(*timer_args_ptr)->is_avail = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*timer_args_ptr == NULL) {
|
|
PHL_ERR("%s: get available timer failed!\n", __func__);
|
|
break;
|
|
}
|
|
|
|
(*timer_args_ptr)->phl_info = phl_info;
|
|
(*timer_args_ptr)->led_manage_mask = 0;
|
|
(*timer_args_ptr)->timer_alive = true;
|
|
(*timer_args_ptr)->delay_unit = 0;
|
|
}
|
|
|
|
(*timer_args_ptr)->led_manage_mask |= BIT(led_id);
|
|
led_info->toggle_timer_args = *timer_args_ptr;
|
|
|
|
break;
|
|
|
|
default:
|
|
status = RTW_PHL_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static enum rtw_phl_status _phl_led_ctrl_event_hdlr(struct phl_info_t *phl_info,
|
|
enum rtw_led_event event)
|
|
{
|
|
enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
|
|
struct phl_led_event_args_t *event_args = NULL;
|
|
struct phl_led_ctrl_t *led_ctrl =
|
|
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
|
|
|
|
u8 args_idx;
|
|
enum rtw_led_id led_id;
|
|
struct phl_led_info_t *led_info = NULL;
|
|
struct rtw_led_action_args_t *action_args = NULL;
|
|
struct phl_led_timer_args_t *timer_args = NULL;
|
|
|
|
if(event >= RTW_LED_EVENT_LENGTH){
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: invalid event(0X%X) >= RTW_LED_EVENT_LENGTH(0X%X).\n",
|
|
__func__, event, RTW_LED_EVENT_LENGTH);
|
|
return RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: event == 0X%X\n", __func__,
|
|
event);
|
|
|
|
/* set state */
|
|
switch (event) {
|
|
case RTW_LED_EVENT_SW_RF_ON:
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: set state sw rf on\n",
|
|
__func__);
|
|
led_ctrl->state |= RTW_LED_STATE_SW_RF_ON;
|
|
break;
|
|
|
|
case RTW_LED_EVENT_SW_RF_OFF:
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: set state sw rf off\n",
|
|
__func__);
|
|
led_ctrl->state &= ~RTW_LED_STATE_SW_RF_ON;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* handle event */
|
|
event_args =
|
|
led_ctrl->event_args_list_arr[event]; /* event_args = list head */
|
|
for (; event_args != NULL; event_args = event_args->next) {
|
|
if (!(event_args->state_condition &
|
|
(led_ctrl->state | RTW_LED_STATE_IGNORE)))
|
|
continue;
|
|
|
|
timer_args = NULL;
|
|
|
|
for (args_idx = 0; args_idx < event_args->action_args_arr_len;
|
|
args_idx++) {
|
|
|
|
action_args = &(event_args->action_args_arr[args_idx]);
|
|
led_id = action_args->led_id;
|
|
led_info = &(led_ctrl->led_info_arr[led_id]);
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_action_hdlr(
|
|
phl_info, led_id, action_args->led_action,
|
|
&(action_args->toggle_args), &timer_args)) {
|
|
|
|
status = RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
}
|
|
|
|
if (timer_args == NULL)
|
|
continue;
|
|
|
|
timer_args->delay_unit = event_args->toggle_delay_unit;
|
|
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_toggle_hdlr(timer_args))
|
|
status = RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static enum phl_mdl_ret_code _phl_led_module_init(void *phl, void *dispr,
|
|
void **priv)
|
|
{
|
|
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
|
|
void *drv_priv = phl_to_drvpriv(phl_info);
|
|
struct phl_led_ctrl_t *led_ctrl = NULL;
|
|
|
|
enum rtw_led_id led_id = 0;
|
|
enum rtw_led_event event_id = 0;
|
|
|
|
struct phl_led_info_t *led_info = NULL;
|
|
|
|
struct rtw_led_intervals_t *intervals = NULL;
|
|
u8 intervals_idx = 0, i = 0;
|
|
|
|
struct phl_led_timer_args_t *timer_args = NULL;
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_init()\n");
|
|
|
|
if (NULL == (led_ctrl = _os_mem_alloc(drv_priv,
|
|
sizeof(struct phl_led_ctrl_t)))) {
|
|
|
|
PHL_ERR("%s: alloc buffer failed!\n", __func__);
|
|
phl_info->led_ctrl = NULL;
|
|
return MDL_RET_FAIL;
|
|
}
|
|
|
|
*priv = phl;
|
|
phl_info->led_ctrl = led_ctrl;
|
|
|
|
/* set default value in led_ctrl */
|
|
led_ctrl->state = 0;
|
|
|
|
for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
|
|
led_info = &(led_ctrl->led_info_arr[led_id]);
|
|
|
|
led_info->ctrl_mode = RTW_LED_CTRL_NOT_SUPPORT;
|
|
led_info->reg_ctrl_mode = RTW_LED_CTRL_NOT_SUPPORT;
|
|
led_info->curr_opt = RTW_LED_OPT_UNKNOWN;
|
|
led_info->toggle_interval_counter = 0;
|
|
led_info->toggle_start_delay_counter = 0;
|
|
led_info->toggle_start_delay_over = false;
|
|
led_info->toggle_loop_counter = 0;
|
|
led_info->toggle_curr_interval_idx = 0;
|
|
led_info->toggle_timer_args = NULL;
|
|
led_info->toggle_args = NULL;
|
|
}
|
|
|
|
for (event_id = 0; event_id < RTW_LED_EVENT_LENGTH; event_id++) {
|
|
led_ctrl->event_args_list_arr[event_id] = NULL;
|
|
}
|
|
|
|
for (intervals_idx = 0; intervals_idx < PHL_LED_INTERVALS_ARR_LEN_MAX;
|
|
intervals_idx++) {
|
|
|
|
intervals = &(led_ctrl->intervals_arr[intervals_idx]);
|
|
|
|
intervals->interval_arr = NULL;
|
|
intervals->len = 0;
|
|
}
|
|
|
|
for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
|
|
if (NULL == (timer_args = _os_mem_alloc( drv_priv,
|
|
sizeof(struct phl_led_timer_args_t)))) {
|
|
|
|
PHL_ERR("%s: alloc #%d timer buffer failed!\n", __func__, i);
|
|
led_ctrl->toggle_timer_args[i] = NULL;
|
|
continue;
|
|
}
|
|
|
|
timer_args->phl_info = phl_info;
|
|
|
|
_os_init_timer(drv_priv, &(timer_args->timer),
|
|
_phl_led_timer_cb, timer_args, "phl_led_timer");
|
|
|
|
timer_args->delay_unit = 0;
|
|
timer_args->timer_alive = false;
|
|
timer_args->is_avail = true;
|
|
timer_args->led_manage_mask = 0;
|
|
|
|
led_ctrl->toggle_timer_args[i] = timer_args;
|
|
}
|
|
|
|
return MDL_RET_SUCCESS;
|
|
}
|
|
|
|
static void _phl_led_module_deinit(void *dispr, void *priv)
|
|
{
|
|
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
|
|
void *drv_priv = phl_to_drvpriv(phl_info);
|
|
struct phl_led_ctrl_t *led_ctrl =
|
|
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
|
|
|
|
enum rtw_led_event event = 0;
|
|
struct phl_led_event_args_t *event_args = NULL;
|
|
struct phl_led_event_args_t *event_args_next = NULL;
|
|
|
|
struct rtw_led_intervals_t *intervals = NULL;
|
|
u8 intervals_idx = 0, i = 0;
|
|
|
|
enum rtw_led_id led_id = 0;
|
|
struct phl_led_info_t *led_info = NULL;
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_deinit()\n");
|
|
|
|
if (led_ctrl == NULL)
|
|
return;
|
|
|
|
/* free event_args_list_arr */
|
|
for (event = 0; event < RTW_LED_EVENT_LENGTH; event++) {
|
|
event_args = led_ctrl->event_args_list_arr[event];
|
|
|
|
if (event_args == NULL)
|
|
continue;
|
|
|
|
while (event_args != NULL) {
|
|
event_args_next = event_args->next;
|
|
|
|
if (event_args->action_args_arr != NULL)
|
|
_os_mem_free(
|
|
drv_priv, event_args->action_args_arr,
|
|
event_args->action_args_arr_len *
|
|
sizeof(struct rtw_led_action_args_t));
|
|
|
|
_os_mem_free(drv_priv, event_args,
|
|
sizeof(struct phl_led_event_args_t));
|
|
|
|
event_args = event_args_next;
|
|
}
|
|
}
|
|
|
|
/* free intervals_arr */
|
|
for (intervals_idx = 0; intervals_idx < PHL_LED_INTERVALS_ARR_LEN_MAX;
|
|
intervals_idx++) {
|
|
|
|
intervals = &(led_ctrl->intervals_arr[intervals_idx]);
|
|
|
|
if (intervals->interval_arr == NULL)
|
|
continue;
|
|
|
|
_os_mem_free(drv_priv, intervals->interval_arr,
|
|
intervals->len * sizeof(u32));
|
|
}
|
|
|
|
/* free all timers */
|
|
for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
|
|
led_info = &(led_ctrl->led_info_arr[led_id]);
|
|
if (led_info->toggle_timer_args == NULL)
|
|
continue;
|
|
|
|
_phl_led_remove_from_timer(led_info, led_id);
|
|
}
|
|
for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
|
|
if (led_ctrl->toggle_timer_args[i] == NULL)
|
|
continue;
|
|
|
|
_phl_led_timer_release(led_ctrl->toggle_timer_args[i]);
|
|
}
|
|
|
|
_os_mem_free(drv_priv, led_ctrl, sizeof(struct phl_led_ctrl_t));
|
|
|
|
phl_info->led_ctrl = NULL;
|
|
}
|
|
|
|
static enum phl_mdl_ret_code _phl_led_module_start(void *dispr, void *priv)
|
|
{
|
|
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
|
|
struct phl_led_ctrl_t *led_ctrl =
|
|
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
|
|
|
|
enum phl_mdl_ret_code ret = MDL_RET_SUCCESS;
|
|
enum rtw_led_id led_id = 0;
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_start()\n");
|
|
|
|
if (led_ctrl == NULL) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
|
|
__func__);
|
|
return MDL_RET_FAIL;
|
|
}
|
|
|
|
for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
|
|
if (RTW_HAL_STATUS_SUCCESS !=
|
|
rtw_hal_led_set_ctrl_mode(
|
|
phl_info->hal, led_id,
|
|
led_ctrl->led_info_arr[led_id].ctrl_mode))
|
|
ret = MDL_RET_FAIL;
|
|
}
|
|
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_PHL_START))
|
|
ret = MDL_RET_FAIL;
|
|
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_SW_RF_ON))
|
|
ret = MDL_RET_FAIL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static enum phl_mdl_ret_code _phl_led_module_stop(void *dispr, void *priv)
|
|
{
|
|
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
|
|
void *drv_priv = phl_to_drvpriv(phl_info);
|
|
struct phl_led_ctrl_t *led_ctrl =
|
|
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
|
|
|
|
enum phl_mdl_ret_code ret = MDL_RET_SUCCESS;
|
|
u8 i = 0;
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_stop()\n");
|
|
|
|
if (led_ctrl == NULL) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
|
|
__func__);
|
|
return MDL_RET_FAIL;
|
|
}
|
|
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_SW_RF_OFF))
|
|
ret = MDL_RET_FAIL;
|
|
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_PHL_STOP))
|
|
ret = MDL_RET_FAIL;
|
|
|
|
for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
|
|
_os_cancel_timer(drv_priv, &(led_ctrl->toggle_timer_args[i]->timer));
|
|
led_ctrl->toggle_timer_args[i]->timer_alive = false;
|
|
led_ctrl->toggle_timer_args[i]->is_avail = true;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static enum phl_mdl_ret_code _phl_led_module_msg_hdlr(void *dispr, void *priv,
|
|
struct phl_msg *msg)
|
|
{
|
|
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
|
|
struct phl_led_ctrl_t *led_ctrl =
|
|
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
|
|
enum phl_msg_evt_id msg_evt_id = MSG_EVT_ID_FIELD(msg->msg_id);
|
|
struct phl_led_timer_args_t *timer_args = NULL;
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"===> _phl_led_module_msg_hdlr()\n");
|
|
|
|
if (IS_MSG_IN_PRE_PHASE(msg->msg_id))
|
|
return MDL_RET_SUCCESS;
|
|
|
|
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_LED)
|
|
return MDL_RET_IGNORE;
|
|
|
|
if(IS_MSG_CANNOT_IO(msg->msg_id))
|
|
return MDL_RET_FAIL;
|
|
|
|
if (led_ctrl == NULL) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
|
|
__func__);
|
|
return MDL_RET_FAIL;
|
|
}
|
|
|
|
if(msg_evt_id < MSG_EVT_LED_EVT_START || msg_evt_id > MSG_EVT_LED_EVT_END){
|
|
if (msg_evt_id == MSG_EVT_LED_TICK) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: MSG_EVT_LED_TICK\n",
|
|
__func__);
|
|
timer_args = (struct phl_led_timer_args_t *)(msg->inbuf);
|
|
|
|
if (!timer_args->timer_alive)
|
|
return MDL_RET_SUCCESS;
|
|
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_toggle_hdlr(timer_args))
|
|
return MDL_RET_FAIL;
|
|
|
|
return MDL_RET_SUCCESS;
|
|
}
|
|
}
|
|
else {
|
|
if (RTW_PHL_STATUS_SUCCESS !=
|
|
_phl_led_ctrl_event_hdlr(phl_info, msg_evt_id - MSG_EVT_LED_EVT_START))
|
|
return MDL_RET_FAIL;
|
|
}
|
|
|
|
return MDL_RET_SUCCESS;
|
|
}
|
|
|
|
static enum phl_mdl_ret_code
|
|
_phl_led_module_set_info(void *dispr, void *priv,
|
|
struct phl_module_op_info *info)
|
|
{
|
|
return MDL_RET_SUCCESS;
|
|
}
|
|
|
|
static enum phl_mdl_ret_code
|
|
_phl_led_module_query_info(void *dispr, void *priv,
|
|
struct phl_module_op_info *info)
|
|
{
|
|
return MDL_RET_SUCCESS;
|
|
}
|
|
|
|
enum rtw_phl_status phl_register_led_module(struct phl_info_t *phl_info)
|
|
{
|
|
#ifdef CONFIG_CMD_DISP
|
|
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
|
|
|
|
struct phl_bk_module_ops bk_ops;
|
|
bk_ops.init = _phl_led_module_init;
|
|
bk_ops.deinit = _phl_led_module_deinit;
|
|
bk_ops.start = _phl_led_module_start;
|
|
bk_ops.stop = _phl_led_module_stop;
|
|
bk_ops.msg_hdlr = _phl_led_module_msg_hdlr;
|
|
bk_ops.set_info = _phl_led_module_set_info;
|
|
bk_ops.query_info = _phl_led_module_query_info;
|
|
|
|
phl_status = phl_disp_eng_register_module(phl_info, HW_BAND_0,
|
|
PHL_MDL_LED, &bk_ops);
|
|
|
|
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
|
|
PHL_ERR("%s register LED module in cmd disp failed\n",
|
|
__func__);
|
|
phl_status = RTW_PHL_STATUS_FAILURE;
|
|
}
|
|
|
|
return phl_status;
|
|
#else
|
|
return RTW_PHL_STATUS_FAILURE;
|
|
#endif
|
|
}
|
|
|
|
void rtw_phl_led_set_ctrl_mode(void *phl, enum rtw_led_id led_id,
|
|
enum rtw_led_ctrl_mode ctrl_mode)
|
|
{
|
|
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
|
|
struct phl_led_ctrl_t *led_ctrl =
|
|
(struct phl_led_ctrl_t *)phl_info->led_ctrl;
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"===> %s()\n", __func__);
|
|
|
|
if (led_ctrl == NULL) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: led_id == %d, ctrl_mode == %d\n", __func__, led_id,
|
|
ctrl_mode);
|
|
|
|
led_ctrl->led_info_arr[led_id].ctrl_mode = ctrl_mode;
|
|
led_ctrl->led_info_arr[led_id].reg_ctrl_mode = ctrl_mode;
|
|
}
|
|
|
|
void rtw_phl_led_set_toggle_intervals(void *phl, u8 intervals_idx,
|
|
u32 *interval_arr, u8 intervals_len)
|
|
{
|
|
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
|
|
struct phl_led_ctrl_t *led_ctrl =
|
|
(struct phl_led_ctrl_t *)phl_info->led_ctrl;
|
|
void *drv_priv = phl_to_drvpriv(phl_info);
|
|
|
|
struct rtw_led_intervals_t *intervals = NULL;
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"===> rtw_phl_led_set_toggle_intervals()\n");
|
|
|
|
if (led_ctrl == NULL) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
if (intervals_idx >= PHL_LED_INTERVALS_ARR_LEN_MAX) {
|
|
PHL_TRACE(
|
|
COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: intervals_idx >= PHL_LED_INTERVALS_ARR_LEN_MAX\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
intervals = &(led_ctrl->intervals_arr[intervals_idx]);
|
|
|
|
/* check if the target intervals_arr has already been set */
|
|
if (intervals->interval_arr != NULL) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: intervals_arr[%d] has already been set. "
|
|
"The new one is going to replace the old one!\n",
|
|
__func__, intervals_idx);
|
|
|
|
_os_mem_free(drv_priv, intervals->interval_arr,
|
|
intervals->len * sizeof(u32));
|
|
|
|
intervals->interval_arr = NULL;
|
|
intervals->len = 0;
|
|
}
|
|
|
|
if (NULL == (intervals->interval_arr = _os_mem_alloc(
|
|
drv_priv, intervals_len * sizeof(u32)))) {
|
|
|
|
PHL_ERR("%s: alloc buffer failed!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
_os_mem_cpy(drv_priv, intervals->interval_arr, interval_arr,
|
|
intervals_len * sizeof(u32));
|
|
intervals->len = intervals_len;
|
|
|
|
return;
|
|
}
|
|
|
|
void rtw_phl_led_set_action(void *phl, enum rtw_led_event event,
|
|
enum rtw_led_state state_condition,
|
|
struct rtw_led_action_args_t *action_args_arr,
|
|
u8 action_args_arr_len, u32 toggle_delay_unit)
|
|
{
|
|
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
|
|
struct phl_led_ctrl_t *led_ctrl =
|
|
(struct phl_led_ctrl_t *)phl_info->led_ctrl;
|
|
void *drv_priv = phl_to_drvpriv(phl_info);
|
|
|
|
struct phl_led_event_args_t *event_args = NULL;
|
|
struct phl_led_event_args_t *event_args_prev = NULL;
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> %s()\n", __func__);
|
|
|
|
if (led_ctrl == NULL) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
if (action_args_arr == NULL) {
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: input -- action_args_arr == NULL\n", __func__);
|
|
return;
|
|
}
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: event == %d, state_condition == %d\n", __func__, event,
|
|
state_condition);
|
|
|
|
event_args =
|
|
led_ctrl->event_args_list_arr[event]; /* event_args = list head */
|
|
|
|
while (event_args != NULL) {
|
|
if (event_args->state_condition == state_condition) {
|
|
PHL_TRACE(
|
|
COMP_PHL_LED, _PHL_INFO_,
|
|
"%s: the event_args_list of event 0x%x already has "
|
|
"a node with state_condition == 0x%x\n",
|
|
__func__, event, state_condition);
|
|
return;
|
|
}
|
|
|
|
event_args_prev = event_args;
|
|
event_args = event_args->next;
|
|
}
|
|
|
|
if (NULL == (event_args = _os_mem_alloc(
|
|
drv_priv, sizeof(struct phl_led_event_args_t)))) {
|
|
|
|
PHL_ERR("%s: alloc buffer failed!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
if (NULL == (event_args->action_args_arr = _os_mem_alloc(
|
|
drv_priv, action_args_arr_len *
|
|
sizeof(struct rtw_led_action_args_t)))) {
|
|
|
|
PHL_ERR("%s: alloc buffer failed!\n", __func__);
|
|
_os_mem_free(drv_priv, event_args,
|
|
sizeof(struct phl_led_event_args_t));
|
|
return;
|
|
}
|
|
|
|
event_args->action_args_arr_len = action_args_arr_len;
|
|
event_args->state_condition = state_condition;
|
|
event_args->toggle_delay_unit = toggle_delay_unit;
|
|
|
|
_os_mem_cpy(drv_priv, event_args->action_args_arr, action_args_arr,
|
|
action_args_arr_len * sizeof(struct rtw_led_action_args_t));
|
|
|
|
event_args->next = NULL;
|
|
|
|
if (event_args_prev == NULL)
|
|
/* the event_args_list was empty */
|
|
led_ctrl->event_args_list_arr[event] = event_args;
|
|
else
|
|
event_args_prev->next = event_args;
|
|
}
|
|
|
|
void phl_led_control(struct phl_info_t *phl_info, enum rtw_led_event led_event)
|
|
{
|
|
#ifdef CONFIG_CMD_DISP
|
|
struct phl_msg msg = {0};
|
|
struct phl_msg_attribute attr = {0};
|
|
|
|
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> rtw_phl_led_control()\n");
|
|
|
|
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_LED);
|
|
|
|
/*
|
|
* led_event here is passed via the msg_evt_id field instead of
|
|
* msg_evt_id due to the following reason:
|
|
*
|
|
* (a) led_event is used for mapping LED events with LED actions, and
|
|
* the mapping can be configured in core layer according to the
|
|
* customized LED table.
|
|
*
|
|
* (b) LED module inside uses led_event as the index of led action
|
|
* arrays, and hence it would be inappropriate to directly replace
|
|
* led_event with msg_evt_id which is not continuous and does not
|
|
* start from zero.
|
|
*
|
|
* (c) It is not worth it to use inbuf with the overhead of dynamic
|
|
* allocation and completion callback only for a number.
|
|
*/
|
|
SET_MSG_EVT_ID_FIELD(msg.msg_id, led_event + MSG_EVT_LED_EVT_START);
|
|
msg.band_idx = HW_BAND_0;
|
|
phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
|
|
#else
|
|
PHL_ERR("phl_fsm not support %s\n", __func__);
|
|
#endif
|
|
}
|
|
|
|
void rtw_phl_led_control(void *phl, enum rtw_led_event led_event)
|
|
{
|
|
phl_led_control((struct phl_info_t *)phl, led_event);
|
|
}
|